【问题标题】:Understanding why race condition happens when only one thread does the write operation了解为什么只有一个线程执行写操作时会发生竞争条件
【发布时间】:2015-03-03 08:16:26
【问题描述】:

我最近问过“Thrown object cannot be caught in a multi-threaded solution”并得到了完美的正确答案。但是,我仍然很困惑为什么只有一个线程执行写操作时会出现竞争条件。我贴一下原来有问题的代码:

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

struct solution_using_thread {
    solution_using_thread()
     : alive_(true), thread_() {
        thread_ = thread([this]() {
            while(alive_);
        });
    }
    ~solution_using_thread() {
        alive_ = false;
        thread_.join();
    }
private:
    bool alive_;
    thread thread_;
};

int main() {
    cout << 0 << endl;
    try {
        solution_using_thread solution;
        throw 1;
    } catch (int i ) {
        cout << i << endl;
    }
    cout << 2 << endl;
}

有时输出只是

0

根据链接的问题,如果我改为使用成员atomic&lt;bool&gt; alive_,则输出将变为预期

0
1
2

现在,我试图解释为什么成员 bool alive_ 会导致未定义行为。

案例 1(大团圆结局):

  • 变量solution被初始化:
    • solution_using_thread 的默认构造函数在主线程中将 alive_ 设置为 true
    • 线程启动,alive_ 的值恰好是第二个线程中的true。所以线程执行卡在while循环中。
    • 在构造函数返回之前,第二个线程已经启动。
  • 我们throw 1
    • solution 的析构函数被调用。 alive_ 在主线程中的值为true
    • thread.join() 阻塞,直到 alive_ 的值与第二个线程同步。
    • 经过一段有限的延迟alive_ 同步后,while 循环终止,第二个线程结束,thread_.join() 返回,堆栈展开愉快地完成。
  • 输出为0 1 2

案例 2(不需要,但至少不是“未定义行为”):

  • 变量solution被初始化:
    • solution_using_thread 的默认构造函数在主线程中将 alive_ 设置为 true
    • 线程启动,alive_ 的值恰好是第二个线程中的false。所以线程执行立即结束。
    • 在构造函数返回之前,第二个线程已经启动。
  • 我们throw 1
    • thread.join() 立即返回,因为线程已经结束。
  • 输出为0 1 2

显然至少还有一种情况,它只打印0。你能描述一下那个案例吗?

【问题讨论】:

  • 一般规则:不要试图理解未定义的行为。绝对不要试图猜测和“解决”它。 Recommended video

标签: exception c++11 race-condition raii stdatomic


【解决方案1】:

标准规定,如果多个线程访问一个变量并且至少一个访问是写入,那么如果该变量不是原子的并且操作不是有序的,则存在数据竞争,并且程序具有数据种族有未定义的行为。

了解这些规则后,编译器可以假设非原子变量没有被乱序修改(否则任何程序都是对源代码的有效解释);在您的示例代码中,这意味着编译器可以简单地假设 alive_ 在繁忙循环内永远不会改变——不过顺便说一下,像这样的非终止循环本身就是未定义的行为。

【讨论】:

    猜你喜欢
    • 2021-02-16
    • 2017-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-04
    • 1970-01-01
    • 2019-09-18
    相关资源
    最近更新 更多