Lockfiles are commonly used for process level mutal exclusion. For example, a cronjob processing hourly logs can hold a lock so in the event it ends up taking more time than an hour, the next hourly job does not clobber the working directory. Databases like Postgres also use lockfiles in their data directories to ensure at most one serving process is handling the data.
On Unix, a very simple way of doing this is to open a file with the desired path
with O_RDWR
and O_EXCL
specified:
int fd = open("/path/to/.lockfile", O_CREAT | O_RDWR | O_EXCL, 0600);
-
O_CREAT
asksopen()
to create the file if it does not exist. -
O_RDWR
requests a read/write handle. -
O_EXCL
ensures that this call creates the file. From the Linuxopen(2)
manpage,…if this flag is specified in conjunction with O_CREAT, and pathname already exists, then open() will fail. When these two flags are specified, symbolic links are not followed: if pathname is a symbolic link, then open() fails regardless of where the symbolic link points to.
Once such an open()
succeeds, it is common practice to put the pid of the
process that holds this “lock” into the opened lockfile before closing the
handle.
In Rust, this can be achieved using the std::fs::OpenOptions::create_new()
function. We can wrap that in this small struct:
|
|
Note that the lockfile will automatically be removed when the LockFile
value
associated with it is dropped.
For a much more interesting implementation, see the CreateLockFile function from Postgres. It is of course way more involved because of failure recovery requirements.