正确的方式使用锁文件作为多个进程之间的锁 [英] proper way to use lock file(s) as locks between multiple processes

查看:137
本文介绍了正确的方式使用锁文件作为多个进程之间的锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个情况,2个不同的进程(我的C + +,其他人在JAVA中做的)是一个作家和一些共享数据文件的读者。所以我试图通过编写类这样的类(编辑:这段代码是破碎,它只是一个例子)避免竞争条件

  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;
}
};

用法:

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

这是一个程序的ofc,其他会有类似的类。
想法是:
1.检查其他程序是否创建了他的我是所有者文件,如果有中断,否则转到2.
2.创建我的我是所有者文件,再次检查其他程序是否创建自己的文件,如果它有删除我的文件,然后断开,否则转到3.
3.做我的阅读,然后删除我的我是所有者文件。



请注意,罕见的事情,当他们都不读或写是确定,但问题是,我仍然看到一个小的竞争条件的机会,因为理论上其他程序可以检查的存在我的锁文件,看到有没有一个,然后我创建我的,其他程序创建自己的,但在FS创建他的文件之前,我再次检查,它不是在那里,那么灾难发生。这就是为什么我添加了一秒延迟,但作为一个CS书呆子,我发现它不知道有这样的代码运行。
Ofc我不希望有人在这里给我写一个解决方案,但我会很高兴,如果有人知道一个可靠代码的链接,我可以使用。
P.S.它必须是文件,cuz我不​​是写整个项目,这是如何安排做的。



PPS:访问数据文件不是读写器,写卡器,读写器,写入器....它可以是读写器,读写器,作者....



PPS:其他进程不是用C ++编写的,所以boost是没有问题的。

mkdir()和 code> rmdir(),可以通过单一系统调用创建和删除原子。你不需要显式地测试锁的存在, em>取得锁定:



$ b sleep

unlock:
rmdir(lockfile)

我相信这甚至可以通过NFS(这通常吸引这种事情)。



但是,你可能还想看看正确的文件锁定,这是加载更好;我在Linux上使用 F_SETLK / F_UNLCK fcntl锁(注意这些不同于群锁,尽管结构的名称)。这允许您正确地阻止,直到锁释放。如果应用程序死机,这些锁也会自动释放,这通常是一件好事。此外,这些将允许您直接锁定共享文件,而不必有一个单独的锁文件。这也在NFS上工作。



Windows具有非常类似的文件锁定功能,并且它还易于使用全局命名的信号量,这对于进程之间的同步非常方便。


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.

解决方案

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.

这篇关于正确的方式使用锁文件作为多个进程之间的锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆