3

名前から何かを推測しているに違いないと思いboost::interprocessます。ドキュメントはここnamed_mutexでグローバルであることを繰り返します。

私はそれを機能させることができません。同じ実行可能ファイルの 2 つのコピーを同時に実行する必要がboost::interprocessあります。そうではありません。また、以下のコードでのデータ ファイルの破損も防ぎません。

ブーストドキュメントのコードは次のとおりです。

#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...

また、デモはファイルに書き込みます。プログラムの 2 つのコピーを実行すると、一部のデータが失われます。

file_nameプログラムの 2 つのコピーを削除して実行するとfile_name、各インスタンスから 100 行を含む書き込みがインターリーブされるはずです。

(注: デモ コードは明らかにofstreamin append モードを使用しておらず、代わりに、このプログラムが実行されるたびにファイルを書き換えるだけなので、ファイルに書き込む 2 つのプロセスをデモで表示したい場合は、その理由を認識しています。なぜそれがうまくいかないのか、しかし私が期待していたのは、上記のコードが相互排除の実行可能なデモンストレーションになることであり、そうではありませんofstream::flush()。 .)

Visual C++ 2008 で Boost 1.53 を使用する

4

1 に答える 1

2

Boost は素晴らしいライブラリであり、ドキュメントに散在するコード例が時々壊れていることがわかりました。少なくともboost::interprocess::named_mutexドキュメントにあるものは、Windows システムでは機能しません。

*デモ コードの一部として常にミューテックスを削除すると、ミューテックスが機能しなくなります。*

これは、少なくともデモ コードでコメントする必要があります。「驚き最小の原則」を破っていますが、なぜそこにあるのか不思議に思っていましたが、慣用的で必要なはずだと思っていました。または、必要に応じて、Joel Spolsky が漏れやすい抽象化と呼ぶものの例です。ミューテックスが本当にWindowsの下のファイルシステムポイントである場合C:\ProgramData、私はそれについて知りたくありません. (確かに、Boost のミューテックスの posix フレンドリーなセマンティクスのような匂いがするため、Win32 API に直接アクセスして、ファイルシステムのタードを持たない単純なミューテックスを実装する代わりに、posix スタイルの実装を使用するようになりました。)

これが実際のデモです:

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

人々がこの名前付きミューテックスを使用する実際のデモを行えるように、この回答に対する批評と編集が大好きです。

デモを使用するには:
- ビルドして 2 つのコピーを実行します。パラメータを渡して、どのインスタンスがどの行を書き込んだかを確認できるようにします (start myexename ABCおよびstart myexename DEFWindows のコマンド プロンプトから)。 .

ここに画像の説明を入力

于 2013-03-09T19:43:15.523 に答える