我正在编写一个程序,我需要确保调用某个特定函数一次不会在多个线程中执行。
在这里,我写了一些简化的伪代码,它完全按照我的实际程序完成。
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循环同时执行不止一次有关,但我不知道这是怎么回事。我的方法有问题吗?有更好的方法吗?
由于
答案 0 :(得分:1)
未专门设计为多线程(多生产者多用户)的queue
需要使用相同的互斥锁序列化eneueue
和dequeue
个操作。
(如果您的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()
。