线程同步:确保按顺序调用函数

时间:2012-08-30 03:51:07

标签: multithreading synchronization

我正在编写一个程序,我需要确保调用某个特定函数一次不会在多个线程中执行。

在这里,我写了一些简化的伪代码,它完全按照我的实际程序完成。

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循环同时执行不止一次有关,但我不知道这是怎么回事。我的方法有问题吗?有更好的方法吗?

由于

2 个答案:

答案 0 :(得分:1)

未专门设计为多线程(多生产者多用户)的queue需要使用相同的互斥锁序列化eneueuedequeue个操作。

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

如果_queue.isEmpty()操作容易出现Time of check to time of use problem,则dequeue的检查也需要受到保护。

即行 object o = _queue.dequeue();
需要被_enqueue_mutex.lock();_enqueue_mutex.unlock();包围。

答案 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()