我是C ++ 11多线程的初学者。我正在处理小代码并遇到了这个问题。这是代码:
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
std::mutex print_mutex;
void function1()
{
std::cout << "Thread1 started" << std::endl;
while (true)
{
std::unique_lock<std::mutex> lock(print_mutex);
for (size_t i = 0; i<= 1000000000; i++)
continue;
std::cout << "This is function1" << std::endl;
lock.unlock();
}
}
void function2()
{
std::cout << "Thread2 started" << std::endl;
while (true)
{
std::unique_lock<std::mutex> lock(print_mutex);
for (size_t i = 0; i <= 1000000000; i++)
continue;
std::cout << "This is function2" << std::endl;
lock.unlock();
}
}
int main()
{
std::thread t1(function1);
std::thread t2(function2);
t1.join();
t2.join();
return 0;
}
我编写的代码具有期望以下输出的直觉:
Thread1启动了Thread2启动
这是 function1
这是功能2
这是功能1
。 。
。
。
但显示的输出如下:
Thread1开始了,Thread2开始了
这是功能1
这是功能1
这是 function1
。
。
。
我哪里错了?
答案 0 :(得分:2)
您的两个主题都在执行以下步骤:
实际上,您无法随时离开进行上下文切换,解锁后会立即锁定。解决方案:交换&#34;锁定&#34;和#34;长空循环&#34;步骤,所以只有&#34; print&#34;步骤将被锁定,调度程序可以在&#34;长空循环期间切换到另一个线程&#34;。
欢迎来到线程!
编辑: Pro Tipp:调试多线程程序很难。但有时值得插入一个普通的printf()来指示锁定和解锁(正确的顺序:锁定,然后printf和printf然后解锁),即使程序看起来是正确的。在这种情况下,您可以看到解锁锁定之间的零差距。
答案 1 :(得分:2)
解锁互斥锁并不能保证等待锁定相同互斥锁的另一个线程会立即获得锁定。
它只保证其他线程 TRY 获取锁定。
在这种情况下,在一个线程中解锁互斥锁后,同一个线程将立即尝试再次锁定它。即使另一个线程耐心地等待,对于互斥锁,它并不能保证其他线程将在这次获胜。刚刚锁定它的同一个线程可以成功立即再次锁定它。
今天,您看到同一个线程总是赢得锁定比赛。明天,你可能会发现它始终是另一个线程。无论如何,当同一个互斥锁之后有多个线程在同一时间内,哪个线程将获取互斥锁时,您无法保证。获胜者取决于您的CPU和其他硬件架构,系统加载的繁忙程度,以及许多其他因素。
答案 2 :(得分:0)
这是一个有效的结果,您的代码不会尝试以任何方式控制执行顺序,只要所有线程在某个时刻执行并且没有问题并且这是合法的结果。
即使你改变了循环和锁定(see here)的顺序,也可能发生这种情况,因为你还没有写过任何尝试使用例如conditional variables或只是silly来控制它的东西。 {3}} atomic_bool
(这是一个愚蠢的解决方案,只是为了演示你如何实际交替并确保它将是布尔来交替运行。