Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

proper way to use lock file(s) as locks between multiple processes

I have a situation where 2 different processes(mine C++, other done by other people in JAVA) are a writer and a reader from some shared data file. So I was trying to avoid race condition by writing a class like this(EDIT:this code is broken, it was just an example)

class ReadStatus
{
    bool canRead;
public:
    ReadStatus()
    {
        if (filesystem::exists(noReadFileName))
        {
            canRead = false;
            return;
        }
        ofstream noWriteFile;
        noWriteFile.open (noWriteFileName.c_str());
        if ( ! noWriteFile.is_open())
        {
            canRead = false;
            return;
        }
        boost::this_thread::sleep(boost::posix_time::seconds(1));
        if (filesystem::exists(noReadFileName))
        {
            filesystem::remove(noWriteFileName);
            canRead= false;
            return;
        }
        canRead= true;
    }
    ~ReadStatus()
    {
        if (filesystem::exists(noWriteFileName))
            filesystem::remove(noWriteFileName);
    }
    inline bool OKToRead()
    {
        return canRead;
    }
};

usage:

ReadStatus readStatus; //RAII FTW
    if ( ! readStatus.OKToRead())
        return;

This is for one program ofc, other will have analogous class. Idea is: 1. check if other program created his "I'm owner file", if it has break else go to 2. 2. create my "I'm the owner" file, check again if other program created his own, if it has delete my file and break else go to 3. 3. do my reading, then delete mine "I'm the owner file".

Please note that rare occurences when they both dont read or write are OK, but the problem is that I still see a small chance of race conditions because theoretically other program can check for the existence of my lock file, see that there isnt one, then I create mine, other program creates his own, but before FS creates his file I check again, and it isnt there, then disaster occurs. This is why I added the one sec delay, but as a CS nerd I find it unnerving to have code like that running. Ofc I don't expect anybody here to write me a solution, but I would be happy if someone does know a link to a reliable code that I can use. P.S. It has to be files, cuz I'm not writing entire project and that is how it is arranged to be done.

P.P.S.: access to data file isn't reader,writer,reader,writer.... it can be reader,reader,writer,writer,writer,reader,writer....

P.P.S: other process is not written in C++ :(, so boost is out of the question.

like image 764
NoSenseEtAl Avatar asked Jun 03 '11 15:06

NoSenseEtAl


People also ask

What is the purpose of locking a file?

File locking is a mechanism that restricts access to a computer file, or to a region of a file, by allowing only one user or process to modify or delete it at a specific time and to prevent reading of the file while it's being modified or deleted.

Can multiple processes access the same file?

During the actual reading and writing, yes. But multiple processes can open the same file at the same time, then write back. It's up to the actual process to ensure they don't do anything nasty. If your writing the processes, look into flock (file lock).

How does NFS file locking work?

With the NFS version 4 protocol, a client user can choose to lock the entire file, or a byte range within a file. z/OS NFS client file locking requests can be managed with the llock(Y|N) parameter on the mount command or as an installation default. z/OS NFS supports only advisory locking.


2 Answers

On Unices the traditional way of doing pure filesystem based locking is to use dedicated lockfiles with mkdir() and rmdir(), which can be created and removed atomically via single system calls. You avoid races by never explicitly testing for the existence of the lock --- instead you always try to take the lock. So:

lock:
    while mkdir(lockfile) fails
        sleep

unlock:
    rmdir(lockfile)

I believe this even works over NFS (which usually sucks for this sort of thing).

However, you probably also want to look into proper file locking, which is loads better; I use F_SETLK/F_UNLCK fcntl locks for this on Linux (note that these are different from flock locks, despite the name of the structure). This allows you to properly block until the lock is released. These locks also get automatically released if the app dies, which is usually a good thing. Plus, these will let you lock your shared file directly without having to have a separate lockfile. This, too, work on NFS.

Windows has very similar file locking functions, and it also has easy to use global named semaphores that are very convenient for synchronisation between processes.

like image 121
David Given Avatar answered Oct 14 '22 09:10

David Given


As far as I've seen it, you can't reliably use files as locks for multiple processes. The problem is, while you create the file in one thread, you might get an interrupt and the OS switches to another process because I/O is taking so long. The same holds true for deletion of the lock file.

If you can, take a look at Boost.Interprocess, under the synchronization mechanisms part.

like image 24
Xeo Avatar answered Oct 14 '22 08:10

Xeo