在多个进程之间使用锁文件作为锁的正确方法

时间:2011-06-03 15:10:22

标签: c++ filesystems race-condition

我有一种情况,其中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;
    }
};

用法:

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

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

请注意,当他们不读或写时很少出现,但问题是我仍然看到竞争条件的可能性很小,因为理论上其他程序可以检查我的锁文件是否存在,看到没有一,然后我创建我的,其他程序创建自己的,但在FS创建他的文件之前我再次检查,它不在那里,然后发生灾难。这就是为什么我添加了一秒延迟,但作为CS书呆子,我发现让代码运行起来令人不安。 Ofc我不希望这里的任何人给我写一个解决方案,但如果有人知道我可以使用的可靠代码的链接,我会很高兴。 附:它必须是文件,因为我不是在编写整个项目,而是它是如何安排完成的。

P.P.S。:访问数据文件不是读者,作家,读者,作家....它可以是读者,读者,作家,作家,作家,读者,作家....

P.P.S:其他过程不是用C ++编写的:(因此,提升是不可能的。

3 个答案:

答案 0 :(得分:7)

On Unices传统的基于纯文件系统的锁定方法是使用mkdir()rmdir()的专用锁文件,可以通过单个系统调用以原子方式创建和删除。你从不明确地测试锁的存在来避免竞争 - 而是你总是试图接受锁。所以:

lock:
    while mkdir(lockfile) fails
        sleep

unlock:
    rmdir(lockfile)

我相信这甚至适用于NFS(这通常很糟糕)。

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

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

答案 1 :(得分:3)

就我所见,你无法可靠地将文件用作多个进程的锁。问题是,当您在一个线程中创建文件时,您可能会得到一个中断,并且操作系统会切换到另一个进程,因为I / O需要很长时间。删除锁定文件也是如此。

如果可以,请查看同步机制部分下的Boost.Interprocess

答案 2 :(得分:1)

虽然我一般反对进行API调用,这些API调用可以从构造函数/析构函数抛出(请参阅boost::filesystem::remove上的文档)或者在没有catch块的情况下进行抛出调用,但这并不是你所要求的。< / p>

如果这是用于Windows,您可以查看Overlapped IO库。否则,您是否考虑过使用shared memory between the processes

编辑:刚看到其他进程是Java。您仍然可以创建一个可以在进程之间共享的命名互斥锁,并使用它来创建围绕文件IO位的锁,这样它们就必须轮流写入。对不起我不懂Java所以我不知道这是否比共享内存更可行。