[![nuget][nuget-badge]][nuget-url] [nuget-badge]: https://img.shields.io/nuget/v/Flock.svg [nuget-url]: https://www.nuget.org/packages/Flock
DotNet provides a mechanism for locking a range of bytes within a file;
using the FileStream.Lock
method. This will soon be available in dotnetcore.
However, it is not possible to do this and have the OS notify when the lock is available; i.e. a blocking lock. Implementing this in fully managed code requires a spinlock of some kind, that is; polling in a loop until we can obtain the lock.
This is possible on Win32 by using the LockFileEx
function and IO completion ports; and on Linux by using advisory locking with
fcntl
, which simply
blocks the calling thread.
This library exposes these native functions and wraps them in a class RangeLock
which models the lifetime of the lock such that disposing a RangeLock
instance
will free its associated lock.
The following will open a file; obtain a lock on the second byte of the file only; and write to that second byte. If another process already has a lock that includes that byte of the file, this code will block on the second line until the lock can be obtained.
using Flock;
...
using (var stream = new FileStream("sample.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
using (var rangeLock = new RangeLock(stream, 1, 1))
{
stream.Seek(1, SeekOrigin.Begin);
stream.Write(new byte[] { (byte)'A' }, 0, 1);
}
This implementation uses Linux's "Open File Descriptor" locks, available since Linux 3.1.5. It would be possible to add an implementation using POSIX advisory locking, however this introduces a problem whereby record locks are associated with the process rather than the file descriptor; and therefore locks may be released unexpectedly.
On both Windows and Linux platforms; caution is advised when locking files on network shares; as performance/feasibility may depend on server implementations.
Despite some of these pitfalls, it's worth noting that Win32's LockFileEx
and Unix
advisory locking are both used in the SQLite project
which gives some indication as to their usefulness.
- There's no timeout to the lock; and no way to cancel the wait! This could be done on Windows
by using
CancelSynchronousIo
and on Linux perhaps with a signal. - It might be nice to have an
async
interface to this to prevent blocking the thread. - No OSX implementation - advisory file locking may behave differently on this platform and I have no way of testing this.