如何最好地编写使用相同互斥锁的多个函数

时间:2013-11-05 02:45:24

标签: c++

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

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

3 个答案:

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

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

1。使用std::recursive_mutex

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

尽管使用lock_guardunique_lock,请不要使用锁定/解锁对乱丢您的代码。

2。让foo()把一个守卫作为参数

像这样重写foo()

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

这样,在没有锁定互斥锁的情况下调用foo()是不可能的。 lock_guard对象是一个标记,表示foo()只能通过同步调用。当然,通过锁定一个不相关的互斥锁仍然可能搞砸了(如果你正在实现类的方法,那么很少见,只有一个互斥锁是可见的)。

您可以在this Andrei's pre-C++-11 article上查看此方法的更多详细信息。