我很少想到两个连续表达式之间发生了什么,在对函数的调用和它的主体的第一个表达式的执行之间,或者在对构造函数的调用和它的初始化程序的执行之间发生了什么。然后我开始阅读并发...
1。)连续两次调用具有相同可调用性的std::thread
构造函数(例如函数,函数,lambda),其主体以std::lock_guard
初始化开始,具有相同的std::mutex
对象,标准是否保证与第一个thread
构造函数调用相对应的线程首先执行受锁保护的代码?
2.。)如果标准没有做出保证,那么第二个thread
构造函数调用对应的线程是否有理论或实际可能首先执行受保护的代码? (例如,在执行初始化程序或第一个thread
构造函数调用的主体期间加载了大量系统)
以下是全局std::mutex
对象m
以及已初始化为unsigned
的全局num
1
。函数foo
的正文大括号{
和std::lock_guard
之间只有空格。在main
中,有两个std::thread
s t1
和t2
。 t1
首先调用线程构造函数。 t2
调用线程构造函数。每个线程都使用指向foo
的指针构造。 t1
使用foo
参数unsigned
调用1
。 t2
使用foo
参数unsigned
调用2
。根据哪个线程首先锁定mutex
,num
的值在两个线程执行了受锁保护的代码之后将是4
或3
。如果num
击败4
,则t1
将等于t2
。否则,num
将等于3
。我通过循环并在每个循环结束时将num
重置为1
来对此进行了100,000次试验。 (据我所知,结果不是也不应该依赖于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
等于100000
,结果t1
每次都赢得比赛。但这些试验并没有证明什么。
3。)标准命令“首先调用thread
构造函数”是否总是暗示“首先调用传递给thread
构造函数的可调用对象”?
4。)标准命令“首先调用传递给thread
构造函数的callable”总是暗示“首先锁定mutex
”;假设在callable的主体内,没有代码依赖于在std::lock_guard
初始化的行之前传递给callable的参数? (还排除任何可调用的本地static
变量,如调用次数的计数器,可用于故意延迟某些调用。)
答案 0 :(得分:3)