QLockFile Class
The QLockFile class provides locking between processes using a file. More…
| Header | #include <QLockFile> |
|---|---|
| CMake | target_link_libraries(app PRIVATE Nt::Core) |
| Module | Nt Core C++ Classes |
List of all members, including inherited members
Public Types
| enum | LockError |
Public Functions
| QLockFile(const QString &fileName) | |
| ~QLockFile() | |
| bool | lock() |
| bool | tryLock(int timeout = 0) |
| bool | tryLock(std::chrono::milliseconds timeout) |
| void | unlock() |
| void | setStaleLockTime(int staleLockTime) |
| int | staleLockTime() const |
| void | setStaleLockTime(std::chrono::milliseconds value) |
| std::chrono::milliseconds | staleLockTimeAsDuration() const |
| QString | fileName() const |
| bool | isLocked() const |
| bool | getLockInfo(qint64 *pid, QString *hostname, QString *appname) const |
| bool | removeStaleLockFile() |
| LockError | error() const |
Detailed Description
A lock file can be used to prevent multiple processes from accessing a same resource. For instance, a configuration file on disk, or a socket, a port, a region of shared memory...
Serialization is only guaranteed if all processes that access the shared resource use QLockFile, with the same file name.
QLockFile supports two use cases: protecting a resource for a short period of time (a few seconds at most) and for a long time.
QLockFile lockFile("/tmp/app.lock");
if (lockFile.tryLock(2000)) {
useResource();
lockFile.unlock();
} else if (lockFile.error() == QLockFile::LockFailedError) {
qint64 pid;
QString host, app;
lockFile.getLockInfo(&pid, &host, &app);
}
The lock file is created with the process id, application path and host name of the owner in it, so that other processes can find out who holds the lock. If the owning process dies without unlocking, the lock file is detected as stale: on the same host, because its process no longer exists (or the pid belongs to another program), and on any host once the file is older than staleLockTime(). A stale lock is then removed, with a second lock file named .rmlock making sure that two processes do not remove it at the same time.
The file is created atomically: it is written under a temporary name in the same directory and then hard linked to the lock file name, so that other processes never see a partial file. If the file system does not support hard links, the lock file is created directly.
Differences from Qt
Calling lock() or tryLock() on a lock that this object already holds prints a warning and fails with LockFailedError instead of waiting. While waiting, the polling interval starts at 10 ms and doubles up to half a second. An unlock() that finds the lock file replaced by another process leaves the other file alone. The application path in the lock file is the executable path from /proc, and a lock file whose application name is not an absolute path is not checked for a reused pid. The lock is not re-created if the file is removed by another process.
Member Type Documentation
enum QLockFile::LockError
This enum describes the result of the last call to lock() or tryLock().
| Constant | Description |
|---|---|
QLockFile::NoError | The lock was acquired successfully. |
QLockFile::LockFailedError | The lock could not be acquired because another process holds it. |
QLockFile::PermissionError | The lock file could not be created, for lack of permissions in the parent directory. |
QLockFile::UnknownError | Another error happened, for instance a full partition prevented writing out the lock file, or the directory of the lock file does not exist. |
Member Function Documentation
QLockFile::QLockFile(const QString &fileName)
Constructs a new lock file object. The object is created in an unlocked state. When calling lock() or tryLock(), a lock file named fileName will be created, if it doesn't already exist.
QLockFile::~QLockFile()
Destroys the lock file object. If the lock was acquired, this will release the lock, by deleting the lock file.
LockError QLockFile::error() const
Returns the lock file error status.
If tryLock() returns false, this function can be called to find out the reason why the locking failed.
See also tryLock().
QString QLockFile::fileName() const
Returns the name of the lock file, as given to the constructor.
This function was introduced in 6.6.
bool QLockFile::getLockInfo(qint64 *pid, QString *hostname, QString *appname) const
Retrieves information about the current owner of the lock file.
If tryLock() returns false, and error() returns LockFailedError, this function can be called to find out more information about the existing lock file: pid is the process id of the process that created it, hostname the host it ran on and appname the application it ran. Returns true if the information could be retrieved, in which case the outputs that are not nullptr are set; otherwise returns false.
See also tryLock() and error().
bool QLockFile::isLocked() const
Returns true if the lock was acquired by this QLockFile instance, otherwise returns false.
See also lock(), unlock() and tryLock().
bool QLockFile::lock()
Creates the lock file. If another process (or thread) has created the lock file already, this function will block until that process (or thread) releases it. Calling this function multiple times on the same lock from the same thread without unlocking first is not allowed.
Returns true if the lock was acquired, false if it could not be acquired due to an unrecoverable error, such as no permissions in the parent directory.
See also unlock(), tryLock() and error().
bool QLockFile::removeStaleLockFile()
Attempts to forcefully remove an existing lock file.
Calling this is not recommended when protecting a short-lived operation: QLockFile already takes care of removing lock files after a crash, based on a time-out and a check that the process that created the lock file is still running. Also, this function is not guaranteed to remove the lock file if it is held by another process; it only deletes the file. The lock file must not be locked by this object.
Returns true if the lock file was removed.
See also setStaleLockTime() and getLockInfo().
void QLockFile::setStaleLockTime(int staleLockTime)
Sets the time in milliseconds after which a lock file is considered stale to staleLockTime. The default value is 30000, i.e. 30 seconds. If your application typically keeps the file locked for more than 30 seconds (for instance while saving megabytes of data for 2 minutes), you should set a bigger value using setStaleLockTime().
The value is used by lock() and tryLock() in order to determine when an existing lock file is considered stale, i.e. left over by a crashed process. This is done by checking the modification time of the lock file, in addition to checking whether the process that created it still exists on the same host. A value of 0 or less disables the check of the modification time.
See also staleLockTime().
void QLockFile::setStaleLockTime(std::chrono::milliseconds value)
This is an overloaded function.
Sets the time after which a lock file is considered stale to value.
This function was introduced in 6.2.
See also staleLockTimeAsDuration().
int QLockFile::staleLockTime() const
Returns the time in milliseconds after which a lock file is considered stale.
See also setStaleLockTime().
std::chrono::milliseconds QLockFile::staleLockTimeAsDuration() const
Returns the time after which a lock file is considered stale, as a duration.
This function was introduced in 6.2.
See also staleLockTime() and setStaleLockTime().
bool QLockFile::tryLock(int timeout = 0)
Attempts to create the lock file. This function returns true if the lock was obtained; otherwise it returns false. If another process (or thread) has created the lock file already, this function will wait for at most timeout milliseconds for the lock file to become available.
Note: Passing a negative number as the timeout is equivalent to calling lock(), i.e. this function will wait forever until the lock file can be locked if timeout is negative.
If the lock was obtained, it must be released with unlock() before another process (or thread) can successfully lock it.
Calling this function multiple times on the same lock from the same thread without unlocking first is not allowed; it fails.
bool QLockFile::tryLock(std::chrono::milliseconds timeout)
This is an overloaded function.
Tries to create the lock file like tryLock(int), waiting for at most timeout. A negative timeout waits for as long as it takes.
This function was introduced in 6.2.
void QLockFile::unlock()
Releases the lock, by deleting the lock file. Calling this function without having successfully obtained the lock is a no-op.