本页内容

QLockFile Class

QLockFile 类通过文件在进程之间提供锁定功能。更多内容...

头文件: #include <QLockFile>
CMake: find_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(mytarget PRIVATE Qt6::Core)
qmake: QT += core

公共类型

enum LockError { NoError, LockFailedError, PermissionError, UnknownError }

公共函数

QLockFile(const QString &fileName)
~QLockFile()
QLockFile::LockError error() const
QString fileName() const
bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const
bool isLocked() const
bool lock()
bool removeStaleLockFile()
void setStaleLockTime(int staleLockTime)
(since 6.2) void setStaleLockTime(std::chrono::milliseconds staleLockTime)
int staleLockTime() const
(since 6.2) std::chrono::milliseconds staleLockTimeAsDuration() const
bool tryLock(int timeout)
(since 6.2) bool tryLock(std::chrono::milliseconds timeout = std::chrono::milliseconds::zero())
void unlock()

详细说明

锁文件可用于防止多个进程同时访问同一资源。例如,磁盘上的配置文件、套接字、端口或共享内存区域……

只有当所有访问共享资源的进程都使用 QLockFile 且文件路径相同时,才能保证序列化。

QLockFile 支持两种用例:保护资源以进行短期操作(例如,在保存新设置之前验证配置文件是否已更改),以及对资源进行长期保护(例如,用户在编辑器中打开的文档),保护时间不限。

在保护短期操作时,可以调用lock()并等待任何正在运行的操作结束。然而,在长期保护资源时,应用程序应始终先调用setStaleLockTime(0ms),然后以较短的超时时间调用tryLock(),以便提醒用户该资源已被锁定。

如果持有锁的进程崩溃,锁文件将保留在磁盘上,并可能永久阻止其他任何进程访问共享资源。因此,QLockFile 会根据写入文件中的进程 ID 尝试检测此类“过期”的锁文件。 为了应对在此期间进程 ID 被重用的情况,会将当前进程名称与锁文件中该进程 ID 对应的进程名称进行比对。如果进程名称不同,则认为该锁文件已过期。 此外,还会考虑锁文件的最后修改时间(默认值为30秒,适用于短暂操作的用例)。若发现锁文件已过期,则将其删除。

因此,对于需要长期保护资源的使用场景,应调用setStaleLockTime(0),当tryLock()返回LockFailedError 时,应通知用户文档已被锁定,并可使用getLockInfo()获取更多详细信息。

限制

对于大多数环境和文件系统而言,QLockFile 的实现通常是安全的。但在某些情况下,它可能会错误地判定锁定文件已过期(实际上并非如此)、未能检测到过期文件,或在锁定时发生竞争条件。本节记录了这些问题。

主要有两种缓解策略:选择合适的、非零的staleLockTime(),以及选择常规的本地文件系统来存储锁定文件(例如,如果在 Unix 系统上以 root 身份运行,则使用/var/lock ,或者使用runtime location )。 对于 QLockFile 的某些用例,上述方法可能无法实现,例如当使用 QLockFile 来指示用户提供的文件路径正在被编辑时。

非持久性机器 ID

QLockFile 使用机器的唯一 ID 来区分当前机器上的锁和在不同主机上运行的进程的锁。 如果机器 ID 随时间变化(例如在具有临时存储的系统上,这些系统必须在每次启动时生成一个新的 ID),QLockFile 将无法在重启后检测到锁文件已过期。

相反,如果两台不同的机器具有冲突的机器 ID(例如,克隆的系统映像或从备份中恢复),并向 QLockFile 提供网络路径,则该类可能会错误地认为锁已过期,而实际上并非如此。

缺乏原生锁定机制

QLockFile 使用操作系统特有的调用,向其他进程和线程指示锁处于活动状态(而非过期),即使超出了 `staleLockTime()` 的设置范围。 在某些网络或虚拟文件系统(如 Linux 和 macOS 上的 FUSE)中,当使用不同文件系统访问同一文件且原生锁未被传递时,或者在某些会阻塞必要系统调用的环境中,此功能可能不可用。

如果缺少原生锁定支持,QLockFile 将完全依赖锁文件本身的存在、修改时间及其内容。在这种情况下,如果当前锁定该资源的进程在调用 `staleLockTime()` 后仍继续持有该资源,QLockFile 将抢占该锁。

网络文件系统

网络环境中是否支持原生文件锁定并未明确规定:某些实现中,所有访问该文件系统的客户端都支持原生锁定;另一些实现中,本地系统可能仅支持其自身进程的锁定,但不会通过网络共享锁定;还有一些实现中,即使在同一主机内部也不存在原生锁定。 此外,对于同一文件,可能存在部分客户端参与网络锁定,而另一些则不参与的情况。如果网络不支持跨网络锁定,QLockFile 将遵循上述关于缺乏原生锁定时所描述的限制。

此外,如果锁定文件包含另一台主机的标识,QLockFile 将无法确认持有锁定的进程是否仍在运行,因此需要等待staleLockTime() 处理该进程因非正常退出而导致的异常。

通过同一路径访问不同的实际文件

两个进程可能对文件系统有不同的视图,导致相同的文件路径在文件系统中对应不同的文件。在这种情况下,两个 QLockFile 对象很可能都能成功创建锁,但不会相互排斥。如果锁文件所保护的资源仍在它们之间共享,这可能会导致冲突。

这种情况最常出现在容器中(见下文),但并非仅限于容器。

与容器共享的文件

在某些容器实现中,可以隐藏某些进程的存在(例如,Linux 的“PID 命名空间”功能)。 如果某个进程在这样的容器内运行,但与主机系统或另一个容器共享机器 ID,那么位于不同容器(或主机)中的两个进程将无法正确判断锁定进程是否仍在运行。 此外,某些容器控制器可能会替换容器内的启动 ID,导致已启动的进程认为锁定文件总是过期的,无论其时间戳有多新。

在某些其他实现中,容器可能具有临时存储空间,或会刻意创建一个新的机器 ID 以避免冲突。在这种情况下,应用程序将遇到上述关于非持久性机器 ID 的问题。

然而,原生文件锁定通常是有效的(受上文所述文件系统和环境限制的制约),因此即使 QLockFile 确实判定文件显然已过期,它也不会抢占一个被原生锁定的锁文件。

未使用相同协议的访问

QLockFile 无法与在本类实现的协议之外对锁文件所做的修改进行互操作。这包括由其他工具(如 tmpwatch 及其类似工具)删除锁文件,也包括某些病毒扫描工具或类似工具。

时钟偏差

QLockFile 依赖于锁定文件时间戳的准确性。如果时钟时间向前跳跃,QLockFile 可能会错误地判定锁定文件已过期,而实际上并非如此;反之,如果时钟时间向后跳跃,也会出现类似的误判。

因此,建议所有系统保持网络同步时间,并在启动过程的早期阶段执行此同步操作。这对网络文件系统尤为重要。

成员类型文档

enum QLockFile::LockError

此枚举描述了上次调用lock()或tryLock()的结果。

常量值描述
QLockFile::NoError0成功获取了锁。
QLockFile::LockFailedError1由于另一个进程持有锁,因此无法获取锁。
QLockFile::PermissionError2由于父目录权限不足,无法创建锁文件。
QLockFile::UnknownError3发生了其他错误,例如分区已满导致无法写出锁文件。

成员函数文档

[explicit] QLockFile::QLockFile(const QString &fileName)

创建一个新的锁文件对象。该对象创建时处于未锁定状态。调用lock()或tryLock()时,如果fileName 不存在,则会创建一个名为 的锁文件。

另请参阅 lock() 和unlock()。

[noexcept] QLockFile::~QLockFile()

销毁锁文件对象。如果已获取锁,则通过删除锁文件来释放该锁。

QLockFile::LockError QLockFile::error() const

返回锁定文件的错误状态。

如果tryLock()返回false ,则可以调用此函数来查明锁定失败的原因。

QString QLockFile::fileName() const

返回锁定文件的文件名

bool QLockFile::getLockInfo(qint64 *pid, QString *hostname, QString *appname) const

获取锁定文件当前所有者的信息。

如果 `tryLock()` 返回 `false`,且 `error()` 返回 `LockFailedError`,则可调用此函数以获取有关现有锁文件的更多信息:

  • 应用程序的 PID(由 `pid` 返回)
  • 其运行的hostname (在网络文件系统中很有用),
  • 创建该文件的应用程序名称(通过 `appname` 返回),

请注意,如果没有 PID 与该锁文件匹配的正在运行的应用程序,tryLock() 会自动删除该文件,因此只有当存在 PID 与该锁文件匹配的应用程序时(尽管该应用程序可能与此无关),LockFailedError 才会被调用。

这可用于告知用户锁文件的存在,并让用户选择是否删除它。使用removeStaleLockFile() 删除文件后,应用程序可以再次调用tryLock()。

如果信息成功获取,该函数返回true ;如果锁定文件不存在或不包含预期数据,则返回false。这种情况可能发生在tryLock()调用失败与本次函数调用之间,锁定文件已被删除。若发生此情况,只需再次调用tryLock()即可。

bool QLockFile::isLocked() const

如果锁是由此QLockFile 实例获取的,则返回true ;否则返回false 。

另请参阅 lock()、unlock() 和tryLock()。

bool QLockFile::lock()

创建锁文件。

如果另一个进程(或另一个线程)已经创建了该锁文件,则本函数将阻塞,直到该进程(或线程)释放锁文件为止。

不允许在同一线程上对同一锁多次调用此函数,且未先解锁。当文件被递归锁定时,此函数将导致死锁。

如果成功获取锁,则返回true ;如果因不可恢复的错误(例如父目录无权限)而无法获取锁,则返回false。

另请参阅 unlock() 和tryLock()。

bool QLockFile::removeStaleLockFile()

尝试强制删除现有的锁定文件。

在保护短暂操作时,不建议调用此方法:QLockFile 已负责在锁文件存在时间超过staleLockTime() 后将其删除。

仅当需要长期保护资源时(即使用staleLockTime(0)),且tryLock() 返回LockFailedError ,并且用户同意删除锁文件后,才应调用此方法。

成功时返回true ;若无法删除锁定文件则返回false。这种情况通常发生在Windows系统中,当拥有该锁的应用程序仍在运行时。

void QLockFile::setStaleLockTime(int staleLockTime)

将 `staleLockTime ` 设置为锁定文件被视为过期的毫秒数。默认值为 30000,即 30 秒。 如果您的应用程序通常会将文件锁定超过 30 秒(例如,在 2 分钟内保存数兆字节的数据),则应使用 setStaleLockTime() 设置一个更大的值。

`staleLockTime ` 的值会被 `lock()` 和 `tryLock()` 调用所使用,以确定何时将现有锁文件视为过期文件,即由崩溃进程遗留的文件。当 PID 在此期间被重用时,此机制非常有用,因此检测过期锁文件的一种方法是根据其存在时间过长这一事实。

这是一个重载函数,相当于调用:

setStaleLockTime(std::chrono::milliseconds{staleLockTime});

另请参阅 staleLockTime()。

[since 6.2] void QLockFile::setStaleLockTime(std::chrono::milliseconds staleLockTime)

将锁定文件被视为过期的间隔时间设置为staleLockTime 。默认值为30秒。

如果您的应用程序通常会将文件锁定超过30秒(例如,在2分钟内保存数兆字节的数据),则应使用 setStaleLockTime() 设置一个更大的值。

`staleLockTime()` 的值会被 `lock()` 和 `tryLock()` 调用所使用,以确定何时将现有锁文件视为过期文件(即由崩溃进程遗留的文件)。当 PID 在此期间被重复使用时,此机制非常有用;因此,检测过期锁文件的一种方法是检查该文件是否已存在较长时间。

将此值设置为 0 或负数将禁用对锁文件时间戳的验证。如果锁文件的内容表明加锁进程已不再运行,QLockFile 仍会检测到过期的锁文件。

该函数于 Qt 6.2 中引入。

另请参阅 staleLockTime()。

int QLockFile::staleLockTime() const

返回锁文件被视为过期所需的毫秒数。

另请参阅 setStaleLockTime()。

[since 6.2] std::chrono::milliseconds QLockFile::staleLockTimeAsDuration() const

返回一个 std::chrono::milliseconds 对象,该对象表示锁文件被视为过期所需经过的时间。

该函数在 Qt 6.2 中引入。

另请参阅 ` setStaleLockTime()`。

bool QLockFile::tryLock(int timeout)

尝试创建锁文件。如果成功获得锁,该函数返回true ;否则返回false 。如果另一个进程(或另一个线程)已经创建了该锁文件,该函数将最多等待timeout 毫秒,直到锁文件可用。

注意:将负数作为timeout 参数传递等同于调用lock(),即如果timeout 为负数,则该函数将无限期等待,直到锁文件可以被锁定为止。

如果已获得锁,则必须先使用unlock() 释放锁,另一个进程(或线程)才能成功锁定该文件。

不允许在同一线程上对同一锁多次调用此函数而未先解锁,当尝试递归锁定文件时,此函数将始终返回 false。

另请参阅 lock() 和unlock()。

[since 6.2] bool QLockFile::tryLock(std::chrono::milliseconds timeout = std::chrono::milliseconds::zero())

尝试创建锁文件。如果成功获取锁,该函数返回true ;否则返回false 。如果另一个进程(或另一个线程)已经创建了该锁文件,该函数将最多等待timeout ,直到锁文件可用。

如果成功获取了锁,必须先通过unlock() 释放锁,其他进程(或线程)才能成功锁定该文件。

不允许在同一线程上对同一锁多次调用此函数而未先解锁,当尝试递归锁定文件时,此函数将始终返回 false。

这是一个重载函数。

该函数在 Qt 6.2 中引入。

另请参见 lock() 和unlock()。

void QLockFile::unlock()

通过删除锁文件来释放锁。

如果在未先锁定文件的情况下调用 unlock(),则不会执行任何操作。

另请参阅 lock() 和tryLock()。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.