c ++写入同一文件的多个进程 - 进程间互斥?

时间:2018-03-20 10:19:51

标签: c++ c++11 semaphore file-access

我的问题是:从多个进程写入文件的最佳方式(或至少是一种有效方式)是什么?

注意:我正在使用c ++ 11,我希望它能在任何平台上运行(即仅限纯c ++代码)。

我做了一些研究,这就是我的结论:

  1. 在我的进程中,我有多个线程。使用互斥锁可以在每个进程中轻松处理,以序列化对文件的访问。
  2. c ++ / c ++ 11互斥或条件变量不能用于在进程之间进行序列化。
  3. 我需要某种外部信号量/锁定文件作为" mutex" ...但我不知道该怎么做。
  4. 我见过应用程序使用诸如创建" .lock"文件在使用时。但是对于多个快速访问,似乎这可能不起作用(即,在一个进程已经确定文件不存在之后另一个可以创建它然后第一个进程也将尝试创建它)因为测试和创建文件的操作是不是原子的。

    注意:每个进程总是一次写入一整行。我原本以为这可能足以使操作" atomic" (因为整行会在下一行之前得到缓冲),但这似乎并非如此(除非我的代码有误),因为我(很少)得到一条错误的行。这是我如何写一个代码片段(如果它是相关的):

    // in c'tor
    m_osFile.open("test.txt", std::fstream::out | std::fstream::app)
    
    // in write func (std::string data)
    osFile << data<< std::endl;
    

    这一定是一个常见的问题,但我还没有找到一个可行的解决方案。任何代码片段都是受欢迎的。

4 个答案:

答案 0 :(得分:2)

通常操作系统提供特殊功能来锁定保证是原子的文件(如Linux上的lockf或Windows上的LockFile(Ex))。到目前为止,C ++标准库没有提供这样的功能,因此通过例如提供这种设施的平台独立方法。 Boost.Interprocess

答案 1 :(得分:2)

  

我的问题是:最好的方式是什么(或者至少是有效的方法   方式)从多个进程写入文件?

最好的方法是......不要这样做!

这似乎是一种日志(追加)。我只是让每个进程编写自己的文件,然后在需要时合并它们。至少这是常见的方法,这是理由。

任何类型的进程内锁定都不起作用。即使在某些操作系统(窗口)上关闭,打开的文件也会在操作系统级别进行缓冲。

如果你想要一个可移植的解决方案(“我想让它在任何平台上运行”),你就无法执行文件锁定:你将会遇到甚至可能的性能损失/未定义的行为,具体取决于所使用的文件系统(例如:samba) ,NFS)。

今天,同时并可靠地写入单个文件实际上是一个依赖于系统的活动。

我并不是说这是不可能的 - 数据库引擎和其他应用程序可靠地执行它,但它是一种自定义操作。

作为一个很好的选择,你可以让一个进程充当收集器(由Gem Taylor提出),其余所有作为生产者,但这不是一个可靠的替代方案:日志需要到达磁盘“简单“:如果错误可以让日志不被写入,则日志目的将会丢失。

但是,你可以考虑使用这种方法,解耦流程并让它们之间的消息可靠而有效地交换:如果是这种情况,你可以考虑使用像RabbitMQ这样的消息传递解决方案。

在这种情况下,所有进程都将其“行”发布到消息代理,另外一个进程会消耗此类消息并将其写入文件。

答案 2 :(得分:1)

我可以想象两种情况。由于您没有在问题中指定如何生成流程,我想象两种情况:

  1. 您的第一个流程会产生第二个流程(例如,使用fork())。
  2. 这两个流程在您的环境中单独生成。
  3. 在第一个场景中,您的进程之间对所需资源(互斥锁)的简单互斥访问应该可以正常工作。这将阻止进程访问其他进程正在使用的资源。

    第二种情况有点复杂,需要每个进程都承认另一个进程存在。类似的问题已经在here进行了讨论,它在how to avoid race conditions上提供了一个有趣的链接。我还会考虑为此目的检查O_EXCLO_CREAT标志

答案 3 :(得分:0)

您可以在所有进程之间的共享内存中声明与其关联的文件描述符和互斥(条件?)。