假设我有一些看起来像这样的代码:
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() 中我可以只锁定互斥锁一次?
假设我有一些看起来像这样的代码:
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() 中我可以只锁定互斥锁一次?
通常,您依赖互斥锁是可重入的——也就是说,它可以被同一个线程多次锁定:
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
来获取锁,因为它会在发生异常(或如果您忘记)时正确解锁您的对象。
您可以使用std::lock_guard<std::mutex>
:
void foobar()
{
std::lock_guard<std::mutex> guard(g_mutex);
// ...
} // releases g_mutex automatically
我可以想到两个解决方案:
std::recursive_mutex
这样,如果同一个线程多次锁定互斥锁,就没有问题,您不必在调用函数之前解锁它。
使用lock_guard
或者unique_lock
虽然,不要用锁定/解锁对乱扔你的代码。
像这样重写foo()
:
void foo(lock_guard<mutex>&)
{
// do foo stuff
}
这样就不可能在foo()
没有锁定互斥锁的情况下调用。lock_guard
对象是一个令牌,说只能foo()
用同步调用。当然,仍然有可能通过锁定一个不相关的互斥体来搞砸它(如果你正在实现一个类的方法,这种情况很少见,只有一个互斥体可见被锁定)。
您可以在Andrei 的 C++-11 之前的这篇文章中查看有关此方法的更多详细信息。