我很少考虑在两个连续的表达式之间,在调用函数和执行其主体的第一个表达式之间,或者在调用构造函数和执行其初始化程序之间会发生什么。然后我开始阅读并发......
std::thread
1.) 在对具有相同可调用对象(例如函数、函子、lambda)的构造函数的两次连续调用中,其主体以使用std::lock_guard
相同std::mutex
对象的初始化开始,标准是否保证对应于第一个thread
构造函数调用的线程执行锁-首先是受保护的代码?
2.)如果标准没有做出保证,那么第二个thread
构造函数调用对应的线程是否有任何理论上或实际的可能性首先执行受保护的代码?(例如,在执行初始化程序或第一个thread
构造函数调用的主体期间,系统负载很重)
这是一个全局std::mutex
对象m
和一个unsigned
num
初始化为1
. 函数foo
主体的左大括号{
和std::lock_guard
. 在main
中,有两个std::thread
st1
和t2
。t1
首先调用线程构造函数。t2
第二次调用线程构造函数。每个线程都由一个指向foo
. 带参数的t1
调用。带参数的调用。根据哪个线程锁定第一个,在两个线程都执行了锁保护代码之后,' 的值将是 a或 a 。将等于foo
unsigned
1
t2
foo
unsigned
2
mutex
num
4
3
num
4
如果t1
击败t2
锁定。否则,num
将等于3
。通过循环并在每个循环结束时重置num
为,我对此进行了 100,000 次试验。1
(据我所知,结果不也不应该取决于join()
首先编辑哪个线程。)
#include <thread>
#include <mutex>
#include <iostream>
std::mutex m;
unsigned short num = 1;
void foo(unsigned short par) {
std::lock_guard<std::mutex> guard(m);
if (1 == num)
num += par;
else
num *= par;
}
int main() {
unsigned count = 0;
for (unsigned i = 0; i < 100000; ++i) {
std::thread t1(foo, 1);
std::thread t2(foo, 2);
t1.join();
t2.join();
if (4 == num) {
++count;
}
num = 1;
}
std::cout << count << std::endl;
}
最后,count
equals 100000
,所以t1
每次都赢得比赛。但这些试验并不能证明什么。
3.) 标准要求“首先调用thread
构造函数”是否总是意味着“首先调用传递给thread
构造函数的可调用对象”?
4.) 标准要求“首先调用传递给thread
构造函数的可调用对象”是否总是意味着“首先锁定mutex
”;假设在可调用的主体中,不存在依赖于在std::lock_guard
初始化行之前传递给可调用的参数的代码吗?(还排除任何可调用的局部static
变量,例如调用次数计数器,可用于故意延迟某些调用。)