3

我想我必须从名字中假设一些boost::interprocess不正确的东西。文件在这里重复说named_mutex是全球性的。

我无法让它工作。同一个可执行文件的两个副本应该同时运行,我希望一个名为的库中的一个命名互斥锁boost::interprocess有时实际上可能会阻塞。它没有。它也不能防止以下代码中的数据文件损坏。

这是来自 boost 文档的一些代码:

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <fstream>
#include <iostream>
#include <cstdio>


int main ()
{
   using namespace boost::interprocess;
   try{
      struct file_remove
      {
         file_remove() { std::remove("file_name"); }
         ~file_remove(){ std::remove("file_name"); }
      } file_remover;
      struct mutex_remove
      {
         mutex_remove() { named_mutex::remove("fstream_named_mutex"); }
         ~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); }
      } remover;

      //Open or create the named mutex
      named_mutex mutex(open_or_create, "fstream_named_mutex");

      std::ofstream file("file_name");

      for(int i = 0; i < 10; ++i){

         //Do some operations...

         //Write to file atomically
         scoped_lock<named_mutex> lock(mutex);
         file << "Process name, ";
         file << "This is iteration #" << i;
         file << std::endl;
      }
   }
   catch(interprocess_exception &ex){
      std::cout << ex.what() << std::endl;
      return 1;
   }
   return 0;

这是我对它所做的,所以我可以向自己证明互斥锁正在做某事:

#include <windows.h>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <cstdio>


int main (int argc, char *argv[])
{
   srand((unsigned) time(NULL));

   using namespace boost::interprocess;
   try{
       /*
      struct file_remove
      {
         file_remove() { std::remove("file_name"); }
         ~file_remove(){ std::remove("file_name"); }
      } file_remover;
      */

      struct mutex_remove
      {
         mutex_remove() { named_mutex::remove("fstream_named_mutex"); }
         ~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); }
      } remover;

      //Open or create the named mutex
      named_mutex mutex(open_or_create, "fstream_named_mutex");

      std::ofstream file("file_name");

      for(int i = 0; i < 100; ++i){

         //Do some operations...

         //Write to file atomically
         DWORD n1,n2;
         n1 = GetTickCount();
         scoped_lock<named_mutex> lock(mutex);
         n2 = GetTickCount();
         std::cout << "took " << (n2-n1) << " msec to acquire mutex";
         int randomtime = rand()%10;
         if (randomtime<1) 
            randomtime = 1;
         Sleep(randomtime*100);
         std::cout << " ... writing...\n";
         if (argc>1)
            file << argv[1];
         else
             file << "SOMETHING";
         file << " This is iteration #" << i;
         file << std::endl;
         file.flush(); // added in case this explains the corruption, it does not.
      }
   }
   catch(interprocess_exception &ex){
      std::cout << "ERROR " << ex.what() << std::endl;
      return 1;
   }
   return 0;
}

控制台输出:

took 0 msec to acquire mutex ... writing...
took 0 msec to acquire mutex ... writing...
took 0 msec to acquire mutex ... writing...
took 0 msec to acquire mutex ... writing...

此外,该演示会写入一个文件,如果您运行该程序的两个副本,该文件将丢失一些数据。

我希望如果我删除file_name并运行程序的两个副本,我应该得到交错写入,file_name每个实例包含 100 行。

(注意,演示代码显然没有使用ofstream附加模式,而是在每次程序运行时简单地重写文件,所以如果我们想要演示显示两个进程写入文件,我知道这个原因为什么它不起作用,但我确实期望上面的代码是互斥的可行演示,但事实并非如此.还可以ofstream::flush()包括对一个非常方便且恰当命名的方法的调用,但没有.)

在 Visual C++ 2008 上使用 Boost 1.53

4

1 回答 1

2

事实证明,Boost 是一个很棒的库,它在文档中穿插的代码示例有时可能会被破坏。至少boost::interprocess::named_mutex文档中的 for 在 Windows 系统上不起作用。

*始终在演示代码中删除互斥锁会导致互斥锁不起作用。*

至少应该在演示代码中对此进行注释。它没有通过“最小惊奇原则”,虽然我想知道它为什么在那里,但我认为它一定是惯用的和必要的,实际上是白痴和不必要的。或者,如果有必要,它是 Joel Spolsky 所说的泄漏抽象的一个例子。如果互斥锁真的C:\ProgramData是 Windows 下的文件系统点,我肯定不想知道它,或者知道如果我没有检测到这种情况并清理它,就会留下粪便,这会破坏抽象。(肯定闻起来像 Boost 中互斥体的 posix 友好语义导致它们使用 posix 样式的实现,而不是直接转到 Win32 API 并实现一个没有文件系统垃圾的简单互斥体。)

这是一个工作演示:

#include <windows.h>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <fstream>
#include <iostream>
#include <cstdio>
#include <windows.h>

int main (int argc, char *argv[])
{
   srand((unsigned) time(NULL));

   using namespace boost::interprocess;
   try{
       /*
      // UNCOMMENT THIS IF YOU WANT TO MAKE THIS DEMO IMPOSSIBLE TO USE TO DEMO ANYTHING

      struct file_remove
      {
         file_remove() { std::remove("file_name"); }
         ~file_remove(){ std::remove("file_name"); }
      } file_remover;

      // UNCOMMENT THIS IF YOU WANT TO BREAK THIS DEMO HORRIBLY:

      struct mutex_remove
      {
         mutex_remove() { named_mutex::remove("fstream_named_mutex"); }
         ~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); }
      } remover;
      */

      //Open or create the named mutex
      named_mutex mutex(open_or_create, "fstream_named_mutex");

      std::ofstream file("file_name", std::ios_base::app );
      int randomtime = 0;
      for(int i = 0; i < 100; ++i){

         //Do some operations...

         //Write to file atomically
         DWORD n1,n2;
         n1 = GetTickCount();

         {
         scoped_lock<named_mutex> lock(mutex);
         n2 = GetTickCount();
         std::cout << "took " << (n2-n1) << " msec to acquire mutex";

         randomtime = rand()%10;
         if (randomtime<1) 
            randomtime = 1;

         std::cout << " ... writing...\n";
         if (argc>1)
            file << argv[1];
         else
             file << "SOMETHING";
         file << "...";
         Sleep(randomtime*100);
         file << " This is iteration #" << i;
         file << std::endl;
         file.flush();
         }
         Sleep(randomtime*100); // let the other guy in.
      }
   }
   catch(interprocess_exception &ex){
      std::cout << "ERROR " << ex.what() << std::endl;
      return 1;
   }
   return 0;
}

我希望对此答案进行批评和编辑,以便人们可以使用这个名为 mutex 的工作演示。

使用演示:
- 构建它并运行它的两个副本。传入一个参数,以便您可以查看哪个实例写入了哪些行(start myexename ABC以及start myexename DEF从 Windows 中的命令提示符) - 如果这是您的第二次运行,如果您不希望第二次运行附加到第一次运行,请删除任何名为“file_name”的杂散输出.

在此处输入图像描述

于 2013-03-09T19:43:15.523 回答