学习互斥锁和线程 - 关于竞争条件的问题

Posted

技术标签:

【中文标题】学习互斥锁和线程 - 关于竞争条件的问题【英文标题】:Learning about mutexes and threads - Question regarding race conditions 【发布时间】:2020-05-05 23:25:26 【问题描述】:

我正在自学一些关于并发编程的知识,特别是在 C++ 中使用互斥锁和线程。我写了以下小例子:

#include <iostream>
#include <thread>
#include <mutex>
// #include <chrono>

std::mutex M1,M2;

void task_one () 
    std::cout << "AAAA!\n";
    M1.lock();
    // std::cout << "M1 locked in A\n";
    M2.lock();
    // std::cout << "M2 locked in A\n";
    std::cout << "BBBB!\n";
    M2.unlock();
    // std::cout << "M2 unlocked in A\n";
    M1.unlock();
    // std::cout << "M2 unlocked in A\n";


void task_two () 
    std::cout << "CCCC!\n";
    M2.lock();
    // std::cout << "M2 locked in B\n";
    M1.lock();
    // std::cout << "M1 locked in B\n";
    std::cout << "DDDD!\n";
    // M1.unlock();
    // std::cout << "M1 unlocked in B\n";
    M2.unlock();
    // std::cout << "M2 unlocked in B\n";


int main () 
    std::thread th1 (task_one);
    std::thread th2 (task_two);
    th1.join();
    th2.join();

    // th1.detach();
    // th2.detach();
    // std::chrono::milliseconds timespan(10);
    // std::this_thread::sleep_for(timespan);
    return 0;

我希望这段代码能打印出来

AAAA!
CCCC!

然后在task_one 尝试获取 M2 上的锁时出现死锁(因为task_two 已经获取了该锁)。 但是,它会打印

AAAA!
BBBB!
CCCC!
DDDD!

为什么没有死锁?另外,这是竞争条件的一个例子,还是这段代码是线程安全的?我认为存在竞争条件,因为如果 task_one 可以在 task_two 之前获得 M2 上的锁,那么一切都会执行(也就是说,task_one 将完成,然后允许 task_two 开始)。但是,我运行了很多次,结果相同。另外,如果我关于锁和线程的措辞不正确,请纠正我。

【问题讨论】:

【参考方案1】:

仅仅因为死锁可以发生(正如在发布的代码中确实可以),并不意味着它总是发生。

在您的情况下,task_one 恰好在 task_two 开始之前运行完成。

多线程就是这样:很滑。

【讨论】:

那么如果我对竞态条件的定义(执行顺序影响最终输出)是正确的,那么这段代码就表现出竞态条件?

以上是关于学习互斥锁和线程 - 关于竞争条件的问题的主要内容,如果未能解决你的问题,请参考以下文章

UNIX网络编程:互斥锁和条件变量

信号量,互斥锁,读写锁和条件变量的区别

互斥锁自旋锁读写锁和条件变量

信号量互斥锁和条件变量的区别

互斥锁和条件变量

互斥锁和条件变量