views:

57

answers:

5

What is the best way to atomically lock multiple files? One possibility I've thought of is a simple .lock file in the directory (I'm only protected from other instances of my program; I'm not necessarily trying to thwart other programs from disrespecting the lock.) However, everything I've learned about thread-safety screams "bad idea!" Would this be a safe way to go? Is trying to create a file atomic, so if I succeed in creating it, I know I have the lock? How should I go about this?

I'm writing my own bug tracker (mostly as an exercise, I know I could find good solutions out there,) which stores bugs in files on the network. I envision it kind of like SVN - a single directory gets taken over by the program, and used to hold bugs, revisions, screenshots, etc, all managed by the tracker. I'm assuming SVN has a way to ensure multiple clients don't make commits at the exact same time, etc.

A: 

i recommend Mutex, named mutex is operation system wide.

Andrey
But would it work across a network?
Daniel Rasmussen
@Daniel Rasmussen no
Andrey
*@Andrey* That kind of defeats the point, then. I want multiple users submitting bugs from various places on the network.
Daniel Rasmussen
@Daniel Rasmussen file system well, this is not real option for network access. consider using database (there are free ones), they provide needed facilities.
Andrey
A: 

If you open a file for exclusive access, it will remain locked in that anyone else attempting to open it will fail.

Steven Sudit
So you're suggesting that it's not the *existence* of the ".lock" file, but who holds the access to it?
Daniel Rasmussen
I'm saying lock files are Unix. In Windows, we use the OS, not a convention.
Steven Sudit
But what if you need exclusive access to multiple files at the same time? I can't lock one, then assume I can lock the other, because I may deadlock.
Daniel Rasmussen
You can lock as many as you like, but if you hit one you can't lock, all you have to do is back out by unlocking the rest.
Steven Sudit
@Daniel: My comment to jthg added two other ways that might interest you.
Steven Sudit
A: 

One simple and reliable option is to have your application rename the directory containing those files before it starts using them. It can rename the directory to a random name before it starts and rename it back when it finishes. If the rename is successful, there's no possibility of a conflict.

One disadvantage is that if an application instance fails to rename the directory back, others will be locked out forever. You might be able to come up with some scheme in which the renamed directory name encodes the time it was renamed. If other instances see that a timeout period has passed, they can take control of it.

Have you looked into existing libraries so that you won't have to come up with your own solution and deal with all the edge cases? I unfortunately don't know of any off the top of my head.

jthg
This is reinventing the wheel. There is already a built-in way to lock files.
Steven Sudit
@Steven - there's no built-in way to atomically lock multiple files.
jthg
Well, actually, there is. It's not commonly used, but there's a transactional mode available to file I/O. Having said that, there's really no need to use it here. Worst case, if you wanted to lock an entire directory full of files, you could lock the directory exclusively prior to using the files.
Steven Sudit
@Steven - I see. Thanks.
jthg
@jthg: To be clear, locking the folder would be convention, not just fiat. Nothing stops someone from ignoring the folder and accessing the files. All the lock does is prevent someone from, say, renaming the folder. Having said that, only one process will be allowed to lock the folder at a time, so it's a combination of convention and fiat.
Steven Sudit
+1  A: 

Open each file exclusively, if you find one that can't be opened, then unlock the ones you've already locked. Always lock in alphabetical order to avoid deadlocks.

    private List<FileStream> OpenExclusive(List<string> filenames)
    {
        var streams = new List<FileStream>(filenames.Count);

        try
        {
            filenames.Sort();
            foreach (var name in filenames)
            {
                streams.Add(File.Open(name, 
                  FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None));
            }
            return streams;
        }
        catch (Exception)
        {
            CloseAll(streams);
            return null;
        }
    }

    private void CloseAll(List<FileStream> streams)
    {
        if (streams == null) return;
        foreach (var stream in streams)
        {
            stream.Close();
        }
    }
Ray Henry
A: 

I want multiple users submitting bugs from various places on the network.

Use a database engine.

Perhaps you're right, but then I'm curious how SVN works. It appears to me that there are no servers, all the clients simply access a standard structure of files in your SVN directory.

http://www.pushok.com/soft_svn_vscvs.php says that SVN is based on a BerkleyDB.

ChrisW