Fun with file locking

If you are developing code that uses distributed synchronization or messaging, you sometimes might need to use files as a locking mechanism.  This can be useful because files are persistent (beyond thread, process, or even power session lifetime), and access to them is synchronized between multiple processes if you select the proper file access and sharing modes. 

C# example of taking a file lock:

using (FileStream lockFile = new FileStream(

            lockPath,

            FileMode.OpenOrCreate,

            FileAccess.ReadWrite,

            FileShare.Delete

       ))

{

    // 1. Read lock information from file

    // 2. If not locked, write the lock information

}

If multiple threads or processes are accessing this lock file, the first process to open the file will lock it, blocking others from accessing it (more on why FileShare.Delete and not  FileShare.None in a moment).

This provides the synchronization necessary for safe concurrent access of the file lock.  Clients using the code should try to open the file in a try/catch loop, until a certain timeout is reached, to provide the blocking behavior for the file lock.

Where it gets a bit more interesting is when you are done with the lock, and want to release it.  

A good way to do this is to delete the file (you could also write the file to indicate that you no longer hold the lock, but who wants to have left over lock files?).

Naturally, you’ll want to first open the file with the same exclusive access as you did when locking it, to insure that you are still the one that holds the lock.  Unfortunately, it turns out that there isn’t a way to delete the file using the file handle that you have already opened.  You have to use the File.Delete(string path) API which calls WIN32 DeleteFile() and re-opens the file in order to delete it, or re-open the file with FileOptions.DeleteOnClose (FILE_FLAG_DELETE_ON_CLOSE).  This is where you get into trouble because you already have the file open under a lock to prevent other writers from taking it.

This is where our FileShare.Delete (FILE_SHARE_DELETE) comes in.  By opening the file with this flag, we are prohibiting any lock taking operations from being performed, but allowing the file to be deleted by someone else.

C# example of releasing the file lock:

using (FileStream lockFile = new FileStream(

            lockPath,

            FileMode.OpenOrCreate,

            FileAccess.ReadWrite,

            FileShare.Delete

       ))

{

    // 1. Read lock information from file

 

    // 2. If locked by us, delete the file:

    File.Delete(lockPath);

}

The file will be deleted as soon as our handle to the file is closed at the end of the using {} scope.

Note that this example is meant as a mechanism for cooperative persistent file locking between multiple threads or processes.  It is not meant as a way to guard against malicious or misbehaving code that wants to access the file, because anyone can break the rules while the file is not locked.

The benefit of this approach is that you can create persistent file locks that do not necessarily go away when an owning process terminates, and do not require you to keep the file exclusively locked for the duration of the lock.  You can also provide lock override or timeout semantics on top of this mechanism that would not be possible with an exclusive lock approach.

You can also download the example file lock library and source code (as is, no guarantees, no limitations on use).

Using this library you can create file locks like this:

using (FileLock l = new FileLock(path, lockId, “mylock”))

{

    // do stuff under the file lock …

} // lock automatically released here

Of course, there are other ways to do inter-process locking on Windows, including global mutexes, that may be more appropriate depending on the situation.

If you work with the file system often, be sure to check out the CreateFile documentation: http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx.  CreateFile is really the swiss army knife of Windows - having a good understanding of the access modes, sharing modes, and file flags can unlock a number of useful possibilities for your code. 

Best,

 

Mike

Published 01 March 09 01:33 by Mike Volodarsky
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Abhijit said on March 1, 2009 12:15 PM:
I didn't get why you have to delete the file. Wouldn't you rather take a lock on the file, release it and let other threads in the process use it for mutex?
# Mike Volodarsky said on March 1, 2009 12:44 PM:

I chose to delete it primarily to keep leftover lock files from staying around.

You could write a lock scavenger instead, or delete the file at the end of your "task" if it has a well defined end.  In my scenarios, deleting was is the simplest approach.

Thanks,

Mike

# gOODiDEA.NET said on March 2, 2009 7:18 PM:

.NET C# 4.0 : Named Arguments - New Extension Method “Zip” Back To Basics: Generational Garbage Collection

# gOODiDEA said on March 2, 2009 7:18 PM:

.NETC#4.0:NamedArguments-NewExtensionMethod“Zip”BackToBasics:GenerationalGarb...

# DotNetShoutout said on March 3, 2009 8:33 AM:

Thank you for submitting this cool story - Trackback from DotNetShoutout

# Don said on March 18, 2009 12:00 AM:
Interesting read. Each post has been a great learning experience for me. I enjoy seeing these nuggets of IIS7 knowledge you drop on us.
# Hightechrider said on June 11, 2009 11:59 AM:
Thanks for this code. Suggestion ... you might want to change all the DateTime.Now's to DateTime.UtcNow to avoid any issues around daylight savings time changes when DateTime.Now can go back and repeat time or leap forward. DateTime.Now is best avoided for the most part IMHO.
# Ian said on June 13, 2009 1:59 AM:
DateTime.Now should be replaced with DateTime.UtcNow to avoid issues around daylight savings time changes.
# NewsPeeps said on August 8, 2009 1:21 PM:

Thank you for submitting this cool story - Trackback from NewsPeeps

# Brian said on December 15, 2009 11:29 AM:
Maybe I am missing something, but doesn't this approach suffer from the possibility of a race condition.
# Mike Volodarsky said on January 7, 2010 12:06 AM:
How so?
# said on April 29, 2011 4:46 AM:

Chaussures Nike Sale: http://www.maxpascher.com

# Dedic said on September 7, 2011 7:56 AM:
Seems to me that you should just open the file with create-always and don't worry about deleting it. the next thread to lock the file will just overwrite it. shared delete is more effort than is necessary.

Leave a Comment

(required) 
(optional)
(required) 
Enter the code you see below


About Mike Volodarsky

For the past 5 years, I was the core Program Manager for Microsoft ASP.NET 2.0 and IIS 7.0 products. I drove the design and development of the IIS 7.0 web server core, the IIS FastCGI support, the AppCmd command line tool, the ASP.NET Integrated pipeline, and other special projects around server security, performance, and scalability. Now, I am working on my own on cutting edge web server tech on top of the Microsoft IIS platform, and continue blogging about it here.

About me



Until 2008, I was the core server Program Manager for the IIS 7.0 and ASP.NET 2.0 products at Microsoft.


View Michael Volodarsky's profile on LinkedIn


This is my company. We build expert performance and scalability tech for web applications on the Windows Server stack.
LeanServer Sentinel: Explore and instantly diagnose your production ASP.NET applications Sentinel beta starts on August 3rd! Register now!


Writings



TechNet Magazine
>Top 10 Performance Improvements in IIS 7.0

MSDN Magazine
>IIS 7.0: Build Web Server Solutions with End-To-End Extensibility
>IIS 7.0: Enhance Your Apps with the Integrated ASP.NET Pipeline
>IIS 7.0: Explore The Web Server For Windows Vista And Beyond
>Design and Deploy Secure Web Apps with ASP.NET 2.0 and IIS 6.0
>Fast, Scalable, and Secure Session State Management for Your Web Applications


Tools and Modules

LeechGuard
IconHandler 2.0
DirectoryListing
HttpRedirection
IIS Auth for Wordpress
iisschema.exe
PortCheck.exe v2.0

Popular Posts

- ASP.NET 2.0 Breaking Changes on IIS 7.0
- Develop IIS7 modules and handlers with .NET
- Troubleshoot IIS7 errors like a pro
- Troubleshooting 503 / "service unavailable" errors
- Troubleshooting "server not found" errors
- Create IIS7 sites, applications, and virtual directories
- Run Ruby on Rails with IIS FastCGI
- VS Debugging of ASP.NET applications on Windows Vista
- Stop hot-linking with IIS and ASP.NET

Tags

Search

Go

This Blog

Archives

Good IIS Blogs

Disclaimer

These postings are provided as is with no warranties, and confer no rights. The views expressed in this blog are entirely my own.

Syndication