thecoop
thecoop

Reputation: 46118

Can I use FileStream to implement a file lock?

Can I use the FileStream constructor to ensure only one process accesses a file at a time? Will the following code work?

public static IDisposable AcquireFileLock() {
    IDisposable lockObj;
    do {
        // spinlock - continually try to open the file until we succeed
        lockObj = TryOpenLockFile();

        // sleep for a little bit to let someone else have a go if we fail
        if (lockObj == null) Thread.Sleep(100); 
    }
    while (lockObj == null);

    return lockObj;
}

private static FileStream TryOpenLockFile() {
    try {
        return new FileStream(s_LockFileName, FileMode.Create, FileAccess.Read, FileShare.None);
    }
    catch (IOException) {
        return null;
    }
}

In particular, is the behaviour with FileMode.Create atomic WRT other processes? Is there something else I should be using?

EDIT: to be more specific, this is on the Microsoft CLR using local files on a single machine.

Upvotes: 5

Views: 899

Answers (2)

Steve Townsend
Steve Townsend

Reputation: 54168

This will do what you want. FileShare.None is the important part.

If all the writer apps are on the same computer, you could also use a named Mutex to achieve the same goal without a physical file being needed, or to mediate file access if you don't care who writes to the file last (just that writes are not concurrent). This could save you from having to reopen the file every time, and provide a blocking semantic instead of your Sleep loop (better perf).

Note that any process can squat on your file (Mutex) if the name is not treated as a secret, i.e. information that needs to be kept secure.

Upvotes: 2

Ana Betts
Ana Betts

Reputation: 74652

This will work, given the following caveats:

  • You are on Windows (on Linux via Mono, this doesn't hold up since file locks are advisory, so your method always succeeds)
  • You are accessing a local file (SMB will also probably work, but NFS or WebDAV almost certainly won't)
  • Catching IOException is probably too broad, you need to specifically verify that it failed because of a sharing violation

Upvotes: 1

Related Questions