假设我有一些看起来像这样的代码:
g_mutex
void foo()
{
g_mutex.lock();
...
g_mutex.unlock()
}
void foobar()
{
g_mutex.lock();
...
g_mutex.unlock()
foo();
g_mutex.lock();
...
g_mutex.unlock()
}
我是否可以使用这样的模式,以便在foobar()中我可以锁定互斥锁一次?
答案 0 :(得分:2)
您可以使用std::lock_guard<std::mutex>
:
void foobar()
{
std::lock_guard<std::mutex> guard(g_mutex);
// ...
} // releases g_mutex automatically
答案 1 :(得分:2)
通常,您依赖互斥锁是可重入的 - 也就是说,它可以被同一个线程锁定多次:
void foo() {
g_mutex.lock();
// do foo stuff
g_mutex.unlock();
}
void foobar() {
g_mutex.lock();
foo();
g_mutex.unlock();
}
如果由于某种原因你不想这样做,那么方法会更加混乱,但不建议这样做。这通常只在一个类中完成,您可以在其中限制对私有函数的访问。
void foo_private()
{
// do foo stuff with the assumption that the lock is acquired.
}
void foo() {
g_mutex.lock();
foo_private();
g_mutex.unlock();
}
void foobar() {
g_mutex.lock();
foo_private();
g_mutex.unlock();
}
此外,正如您问题的其他答案所述,您应该使用std::lock_guard
获取锁定,因为它会在发生异常时(或者如果您忘记)正确解锁您的对象。< / p>
答案 2 :(得分:2)
我可以想到两个解决方案:
std::recursive_mutex
这样一来,如果同一个线程多次锁定互斥锁就没有问题,你不必在调用函数之前将其解锁。
尽管使用lock_guard
或unique_lock
,请不要使用锁定/解锁对乱丢您的代码。
像这样重写foo()
:
void foo(lock_guard<mutex>&)
{
// do foo stuff
}
这样,在没有锁定互斥锁的情况下调用foo()
是不可能的。 lock_guard
对象是一个标记,表示foo()
只能通过同步调用。当然,通过锁定一个不相关的互斥锁仍然可能搞砸了(如果你正在实现类的方法,那么很少见,只有一个互斥锁是可见的)。
您可以在this Andrei's pre-C++-11 article上查看此方法的更多详细信息。