我很少想到在两个连续的表达式之间,函数调用和它的主体的第一个表达式的执行之间,或者在构造函数的调用和它的执行之间发生了什么初始化。然后,我开始阅读关于并发...std :: mutex锁定的顺序
1)在连续两次调用std::thread
的构造用相同的可调用(如函数,仿函数,拉姆达),其身体开始有std::lock_guard
初始化与同std::mutex
对象,标准是否保证第一个thread
构造函数调用对应的线程首先执行受锁定保护的代码?如果标准没有作出保证,那么是否存在任何理论上或实践上的可能性,对应于第二个构造函数调用的线程首先执行受保护的代码? (第一thread
构造函数调用的初始化或身体的执行期间例如重系统负载)
这里的一个全局std::mutex
m
对象和全局unsigned
num
初始化为1
。功能foo
的开启支架{
和std::lock_guard
之间只有空白。在main
中,有两个std::thread
和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
构造函数的可调用函数”是否始终暗示“首先锁定mutex
”;前提是在可调用函数体内,不存在代码,该代码依赖于初始化行之前传递给可调用函数的参数吗? (也排除任何可调用的本地static
变量,像所谓的次数的计数器,可用于故意拖延某些呼叫。)
不,是的,不清楚,没有。 –