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不是专门设计为多线程的(多生产者多消费者)将需要使用相同的互斥锁序列化和操作eneueuedequeue

(如果您的queue实现有不同的假设,请在您的问题中说明。)

校验_queue.isEmpty()也需要保护,如果dequeue操作容易出现校验时间到使用时间的问题

也就是说,这条线也
object o = _queue.dequeue();
需要被_enqueue_mutex.lock();和包围_enqueue_mutex.unlock();

于 2012-08-30T03:58:22.593 回答
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 回答