了解为什么只有一个线程执行写操作时会发生竞争条件
Understanding why race condition happens when only one thread does the write operation
我最近问了“”并得到了完美的正确答案。但是,我仍然很困惑为什么只有一个线程执行写操作时会出现竞争条件。让我贴一下原来有问题的代码:
#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<bool> alive_
,输出将变为预期的结果
0
1
2
现在,我正在尝试解释成员 bool alive_
导致未定义行为的原因。
案例 1(大团圆结局):
- 变量
solution
已初始化:
solution_using_thread
的默认构造函数在主线程中将 alive_
设置为 true
。
- 线程启动,
alive_
的值恰好是第二个线程中的true
。所以线程执行卡在了while
循环中。
- 在构造函数returns之前,第二个线程已经启动
- 我们
throw 1
。
solution
的析构函数被调用。 alive_
的值在主线程中是true
。
thread.join()
阻塞,直到 alive_
的值与第二个线程同步。
- 经过一些有限的延迟
alive_
同步后,while 循环终止,第二个线程完成,thread_.join()
returns 和堆栈展开顺利完成。
- 输出为
0 1 2
情况2(不希望,但至少'Undefined Behavior'):
- 变量
solution
已初始化:
solution_using_thread
的默认构造函数在主线程中将 alive_
设置为 true
。
- 线程启动,
alive_
的值恰好是第二个线程中的false
。所以线程执行立即结束。
- 在构造函数returns之前,第二个线程已经启动。
- 我们
throw 1
thread.join()
returns 立即,因为线程已经完成。
- 输出为
0 1 2
显然,至少还有一种情况只打印 0
。你能描述一下那个案例吗?
标准说,如果多个线程访问一个变量并且至少有一个访问是写入,那么如果该变量不是原子的并且操作没有顺序,则存在数据竞争,并且程序具有数据竞争具有未定义的行为。
了解这些规则,编译器可以假定非原子变量不会被乱序修改(否则 任何 程序都是对源代码的有效解释);在您的示例代码中,这意味着编译器可以简单地假设 alive_
在繁忙的循环中永远不会改变——尽管顺便说一句,像这样的非终止循环本身就是未定义的行为。
我最近问了“
#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<bool> alive_
,输出将变为预期的结果
0
1
2
现在,我正在尝试解释成员 bool alive_
导致未定义行为的原因。
案例 1(大团圆结局):
- 变量
solution
已初始化:solution_using_thread
的默认构造函数在主线程中将alive_
设置为true
。- 线程启动,
alive_
的值恰好是第二个线程中的true
。所以线程执行卡在了while
循环中。 - 在构造函数returns之前,第二个线程已经启动
- 我们
throw 1
。solution
的析构函数被调用。alive_
的值在主线程中是true
。thread.join()
阻塞,直到alive_
的值与第二个线程同步。- 经过一些有限的延迟
alive_
同步后,while 循环终止,第二个线程完成,thread_.join()
returns 和堆栈展开顺利完成。
- 输出为
0 1 2
情况2(不希望,但至少'Undefined Behavior'):
- 变量
solution
已初始化:solution_using_thread
的默认构造函数在主线程中将alive_
设置为true
。- 线程启动,
alive_
的值恰好是第二个线程中的false
。所以线程执行立即结束。 - 在构造函数returns之前,第二个线程已经启动。
- 我们
throw 1
thread.join()
returns 立即,因为线程已经完成。
- 输出为
0 1 2
显然,至少还有一种情况只打印 0
。你能描述一下那个案例吗?
标准说,如果多个线程访问一个变量并且至少有一个访问是写入,那么如果该变量不是原子的并且操作没有顺序,则存在数据竞争,并且程序具有数据竞争具有未定义的行为。
了解这些规则,编译器可以假定非原子变量不会被乱序修改(否则 任何 程序都是对源代码的有效解释);在您的示例代码中,这意味着编译器可以简单地假设 alive_
在繁忙的循环中永远不会改变——尽管顺便说一句,像这样的非终止循环本身就是未定义的行为。