1

假设我有一些看起来像这样的代码:

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() 中我可以只锁定互斥锁一次?

4

3 回答 3

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来获取锁,因为它会在发生异常(或如果您忘记)时正确解锁您的对象。

于 2013-11-05T03:08:22.717 回答
2

您可以使用std::lock_guard<std::mutex>

void foobar()
{
    std::lock_guard<std::mutex> guard(g_mutex);
    // ...
} // releases g_mutex automatically
于 2013-11-05T03:06:15.790 回答
2

我可以想到两个解决方案:

1.使用std::recursive_mutex

这样,如果同一个线程多次锁定互斥锁,就没有问题,您不必在调用函数之前解锁它。

使用lock_guard或者unique_lock虽然,不要用锁定/解锁对乱扔你的代码。

2. 使 foo() 将守卫作为参数

像这样重写foo()

void foo(lock_guard<mutex>&)
{
    // do foo stuff
}

这样就不可能在foo()没有锁定互斥锁的情况下调用。lock_guard对象是一个令牌,说只能foo()用同步调用。当然,仍然有可能通过锁定一个不相关的互斥体来搞砸它(如果你正在实现一个类的方法,这种情况很少见,只有一个互斥体可见被锁定)。

您可以在Andrei 的 C++-11 之前的这篇文章中查看有关此方法的更多详细信息。

于 2013-11-05T03:28:34.657 回答