0

特定の関数が呼び出され、一度に複数のスレッドで実行されていないことを確認する必要があるプログラムを書いています。

ここでは、実際のプログラムで行われていることとまったく同じことを行う簡略化された疑似コードをいくつか書きました。

mutex _enqueue_mutex;
mutex _action_mutex;
queue _queue;
bool  _executing_queue;

// called in multiple threads, possibly simultaneously
do_action() {
  _enqueue_mutex.lock()
  object o;
  _queue.enqueue(o);
  _enqueue_mutex.unlock();

  execute_queue();
}

execute_queue() {
  if (!executing_queue) {
    _executing_queue = true;
    enqueue_mutex.lock();
    bool is_empty = _queue.isEmpty();
    _enqueue_mutex.lock();
    while (!is_empty) {
      _action_mutex.lock();

      _enqueue_mutex.lock();
      object o = _queue.dequeue();
      is_empty = _queue.isEmpty();
      _enqueue_mutex.unlock();

      // callback is called when "o" is done being used by "do_stuff_to_object_with_callback" also, this function doesn't block, it is executed on its own thread (hence the need for the callback to know when it's done)
      do_stuff_to_object_with_callback(o, &some_callback);
    }
    _executing_queue = false;
  }
}

some_callback() {
  _action_mutex.unlock();
}

基本的には_action_mutex、while ループでロックされ (lock再度ロックできるようになるまでブロックしていると見なされます)、完了コールバックが呼び出されたときにロックが解除されることが期待されます (some_callback上記のコードで)。

ただし、これは機能していないようです。がdo_action同時に複数回呼び出されると、プログラムがロックアップします。while ループが同時に複数回実行されていることに関連している可能性があると思いますが、それがどのように当てはまるかわかりません。私のアプローチに何か問題がありますか?より良いアプローチはありますか?

ありがとう

4

2 に答える 2

1

マルチqueueスレッド (マルチ プロデューサー、マルチ コンシューマー) 用に特別に設計されていない は、同じミューテックスを使用して と の両方eneueueの操作をシリアル化する必要があります。dequeue

(queue実装に別の前提がある場合は、質問に記載してください。)

操作がチェック時間から使用時間の問題を起こしやすい場合は、チェック_queue.isEmpty()も保護する必要があります。dequeue

つまり、行はand
object o = _queue.dequeue();
で囲まれている必要があります。_enqueue_mutex.lock();_enqueue_mutex.unlock();

于 2012-08-30T03:58:22.593 に答える
1

おそらく、キューに必要なミューテックスは 1 つだけです。また、オブジェクトをデキューすると、おそらくロックの外で処理できます。do_action()これにより、 への呼び出しが長時間ハングするのを防ぐことができます。

mutex moo;
queue qoo;
bool keepRunning = true;

do_action():
{
    moo.lock();
    qoo.enqueue(something);
    moo.unlock(); // really need try-finally to make sure,
    // but don't know which language we are using
}

process_queue():
{
    while(keepRunning)
    {
        moo.lock()
        if(!qoo.isEmpty)
            object o = qoo.dequeue();

        moo.unlock(); // again, try finally needed

        haveFunWith(o);
        sleep(50);
    }
}

次にprocess_queue()、独自のスレッドで呼び出します。

于 2012-08-30T04:07:54.857 に答える