pra*_*ran 5 c++ multithreading mutex
我两天前参加了一次面试.受访的人在C++方面表现很好,但在多线程方面则不然.当他让我为两个线程的多线程编写代码时,其中一个线程打印1,3,5,...和另一个打印2,4,6,... 但是,输出应该是1,2,3,4,5,....所以,我给出了下面的代码(sudo代码)
mutex_Lock LOCK;
int last=2;
int last_Value = 0;
void function_Thread_1()
{
while(1)
{
mutex_Lock(&LOCK);
if(last == 2)
{
cout << ++last_Value << endl;
last = 1;
}
mutex_Unlock(&LOCK);
}
}
void function_Thread_2()
{
while(1)
{
mutex_Lock(&LOCK);
if(last == 1)
{
cout << ++last_Value << endl;
last = 2;
}
mutex_Unlock(&LOCK);
}
}
Run Code Online (Sandbox Code Playgroud)
在此之后,他说"即使没有这些锁,这些线程也能正常工作.这些锁定会降低效率".我的观点是没有锁定会有一个线程将检查(last == 1或2)同时另一个线程将尝试将值更改为2或1的情况.所以,我的结论是它将没有锁定,但这不是一个正确/标准的方式.现在,我想知道谁是正确的,在哪个基础上?
面试官不知道他在说什么。如果没有锁,您将在 和 上进行last竞赛last_value。例如,编译器可以将分配重新排序到last打印和增量之前last_value,这可能会导致另一个线程在陈旧数据上执行。此外,您可以获得交错输出,这意味着两个数字不被换行符分隔。
另一件事,可能会出错的是,编译器可能决定不重新加载last(不太重要)last_value每次迭代,因为无论如何它都不能(安全地)在这些迭代之间进行更改(因为根据 C++11 标准,数据竞争是非法的)并且在以前的标准中没有得到承认)。这意味着面试官建议的代码实际上很有可能创建绝对不执行任何操作的无限循环。
虽然可以在没有 mutices 的情况下使代码正确,但这绝对需要具有适当排序约束的原子操作(在if 语句内部的赋值last和acquire加载上的释放语义)。last
当然,由于有效地序列化整个执行,您的解决方案确实降低了效率。然而,由于运行时几乎完全花费在流输出操作中,而流输出操作几乎肯定是通过使用锁进行内部同步的,因此您的解决方案不会再降低效率。等待代码中的锁实际上可能比忙于等待它更快,具体取决于可用资源(使用原子的非锁定版本在单核机器上执行时绝对会失败)