当互斥量超出范围时,互斥锁会解锁吗?

时间:2013-07-18 16:45:29

标签: c++ multithreading pthreads mutex

简单的问题 - 基本上,我是否必须解锁互斥锁,或者我可以简单地使用范围运算符并且互斥锁会自动解锁?

即:

{ 
    pthread_mutex_lock (&myMutex); 
    sharedResource++; 
} // my mutex is now unlocked?

或者我应该:

{ 
    pthread_mutex_lock (&myMutex); 
    sharedResource++;
    pthread_mutex_unlock (&myMutex);
}

3 个答案:

答案 0 :(得分:17)

在您的示例中,互斥锁不会超出范围;并且编译器无法知道特定函数需要在作用域的末尾调用,因此第一个示例解锁互斥锁。

如果您正在使用(容易出错的)函数来锁定和解锁互斥锁,那么您需要确保始终调用unlock() - 即使受保护的操作会抛出异常。

执行此操作的最佳方法是使用RAII类来管理锁定,就像使用后需要释放的任何其他资源一样:

class lock_guard {
public:
    explicit lock_guard(mutex & m) : m(m) {mutex_lock(m);}
    ~lock_guard() {mutex_unlock(m);}

    lock_guard(lock_guard const &) = delete;
    void operator=(lock_guard &) = delete;

private:
    mutex & m;
};

// Usage
{
    lock_guard lock(myMutex);
    shared_resource++;
} // mutex is unlocked here (even if an exception was thrown)

在现代C ++中,请使用std::lock_guardstd::unique_lock

答案 1 :(得分:2)

使用RAII范围方法要好得多,因为它可以保证即使面对例外或提前返回,互斥锁也将始终处于解锁状态。

如果您可以访问C ++ 11,可以考虑使用std::atomic<int>,在这种情况下,您不需要将其锁定为增量。

答案 2 :(得分:2)

在这种情况下,当此代码超出范围时,不会解锁互斥锁

RAII之后的Mutex锁定器使用的事实是,当非堆分配的对象超出范围时,会自动调用析构函数。然后,一旦锁定互斥锁的对象超出范围,它就会解锁互斥锁。在代码的情况下,在大括号的范围内没有分配任何对象,因此一旦范围结束,就没有可能解锁互斥锁。

例如,使用Qt库中的QMutexLocker,您可以确保在范围结束时解锁您的互斥锁:

{
    QMutexLocker locker(myMutex);
    if(checkSomething())
    {
        return;
    }
    doSomething();
}

此代码类似于:

{
    mutex_lock(myMutex);
    if(checkSomething())
    {
        mutex_unlock(myMutex);
        return;
    }
    doSomething();
    mutex_unlock(myMutex);
}

虽然Brian Neal指出,但它并不能安全地处理checkSomething()doSomething()抛出异常的情况。

Qt QMutexLocker的替代方案是STD的std::lock_guard