2

参照に従ってLinuxでIPCを実行しています(匿名ミューテックスの例)。boost::interprocess::shared_memory_object

でラップされた;shared_memory_objectを保持しながら、 を作成して書き込むサーバープロセスがあります。そして、他の人が書いたものは何でも印刷するクライアントプロセス - この場合、それは.interprocess_mutexscoped_lockint

問題が発生しました。サーバーがミューテックスを保持している間にスリープ状態になると、クライアント プロセスはミューテックスを取得できず、永遠に待機します。

バグのあるサーバーループ:

using namespace boost::interprocess;
int n = 0;
while (1) {
    std::cerr << "acquiring mutex... ";
    {
        // "data" is a struct on the shared mem. and contains a mutex and an int
        scoped_lock<interprocess_mutex> lock(data->mutex);
        data->a = n++;
        std::cerr << n << std::endl;
        sleep(1);
    } // if this bracket is placed before "sleep", everything works
}

サーバー出力:

acquiring mutex... 1
acquiring mutex... 2
acquiring mutex... 3
acquiring mutex... 4

クライアントループ:

while(1) {
   std::cerr << "acquiring mutex... ";
   {
      scoped_lock<interprocess_mutex> lock(data->mutex);
      std::cerr << data->a << std::endl;
   }
   sleep(1);
}

クライアント出力 (永久に待機):

acquiring mutex...

問題は、ブラケットをsleep呼び出しの前の行に移動すると、すべてが機能することです。なんで?ロックされたミューテックスでスリープすると、ミューテックスが永久にロックされるとは思いませんでした。

私が持っている唯一の理論は、カーネルがサーバー プロセスを起動すると、スコープが終了し、ミューテックスが解放されるが、待機中のプロセスには実行の機会が与えられないというものです。その後、サーバーはロックを再取得します...しかし、それはあまり意味がないようです。

ありがとう!

4

2 に答える 2

7

あなたの理論は正しいです。

リンクしたリファレンスの匿名ミューテックスの例の下部を見ると、次のようになります。

ご覧のとおり、ミューテックスはデータを保護するのに役立ちますが、別のプロセスにイベントを通知するのには役立ちません。

ミューテックスをリリースしても、それを待っている可能性のある他の人には通知されません。プロセスが目覚めたばかりなので、ほぼ確実に、より多くの作業を行うためのスケジューリングクォンタムがたくさん残っています。ループしてミューテックスを再取得してから、再びスリープします。これは、クライアントがミューテックス自体を取得する最初の機会です。

サーバーsleep()をスコープ外に移動すると、ミューテックスが解放されている間サーバーがスリープ状態になり、クライアントが自分でミューテックスを実行して取得する機会が与えられます。

sched_yield()プロセッサをあきらめたいが、スコープ内でスリープしたい場合は、(Linuxのみ)を呼び出してみてください。sleep(0)動作する場合もあります。

于 2009-06-10T18:24:25.130 に答える
0

ミューテックスを持って寝るのは間違っています。Mutexは一部のデータ(つまり、data-> a)を保護し、そのデータの読み取り/書き込みの範囲を最小限に抑える必要があります。

于 2009-06-10T18:22:57.053 に答える