std :: mutex如何在不同的线程中解锁?

时间:2017-04-19 05:45:49

标签: c++ multithreading c++14 mutex

我正在阅读二进制信号量和互斥量(Difference between binary semaphore and mutex)之间的差异,我要验证的一件事是,当任务锁定(获取)互斥锁时,它只能解锁(释放)它。如果另一个任务试图解锁互斥锁它没有锁定(因此不拥有),那么遇到错误条件,最重要的是,互斥锁没有解锁,为此我在c ++ 14中创建了下面的代码:< / p>

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;

int counter;
int i;
std::mutex g_pages_mutex;
void increment()
{
    std::cout<<"increment...."<<std::endl;    
    g_pages_mutex.lock();
    bool flag = g_pages_mutex.try_lock();
    std::cout<<"increment Return value is "<<flag<<std::endl;
    counter++;
    std::this_thread::sleep_for(5s);
}
void increment1()
{
    std::this_thread::sleep_for(5s);    
    std::cout<<"increment1...."<<std::endl;       
    g_pages_mutex.unlock();    
    counter++;
    bool flag = g_pages_mutex.try_lock();
    std::cout<<"increment1 Return value is "<<flag<<std::endl;
}
int main()
{
    counter = 0;
    std::thread t(increment);
    std::thread t1(increment1);
    t.join();
    t1.join();
    return 0;
}

然而,通过这个例子,我能够从没有拥有它的线程中解锁互斥锁,所以只是想要有一些理解上的差距,或者这个问题在c ++ 14 std :: mutex中?

3 个答案:

答案 0 :(得分:4)

在调用线程拥有的try_lock(不是递归)上调用std::mutex,在不属于调用线程的互斥锁上调用unlock,并在保持时结束线程互斥体,都会导致未定义的行为。

它可能看起来成功,它可能会失败并抛出异常,它可能会格式化您的硬盘驱动器,它可能会召唤鼻子恶魔,它可能会为您旅行并更正您的代码,或者它可能会做其他事情。就标准而言,任何都是允许的。

答案 1 :(得分:0)

来自cppreference std::mutex(强调我的):

  

如果互斥锁在被任何线程拥有的情况下被销毁,或线程在拥有互斥锁时终止,则程序的行为是未定义的。

来自std::mutex::try_lock上的同一网站和TC points out in their answer

  

如果已经拥有互斥锁的线程调用了try_lock,则行为未定义。

还有std::mutex::unlockTC points out in their answer

  

互斥锁必须由当前执行线程锁定,否则行为未定义。

您的函数和线程都会导致未定义的行为:

  1. increment调用lock()然后调用try_lock():未定义的行为
  2. increment1在拥有互斥锁之前调用unlock():未定义的行为
  3. 如果在线程结束前未调用try_lock(),则从increment中删除unlock()仍会导致未定义的行为。

    您应该更喜欢使用std::lock_guard,或者对于简单的int,您也可以使用std::atomic

答案 2 :(得分:0)

调用unlock的前提条件是持有互斥锁的所有权,根据(标准)30.4.1.2:

  

表达式m.unlock()应格式正确,并具有以下语义:

     

要求:调用线程应拥有互斥锁。

由于执行increment1的线程不拥有互斥锁的所有权,它引爆了未定义的行为。