执行不在线程之间切换 (c++11)
Execution not switching between thread (c++11)
我是 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 started
Thread2 started
This is
function1
This is function2
This is function1
. .
.
.
但是显示的输出如下:
Thread1 started
Thread2 started
This is function1
This is function1
This is
function1
.
.
.
我哪里错了?
您的两个线程都在执行以下步骤:
- 锁定
- 长空循环
- 打印
- 解锁
- 锁定
- 长空循环
- (以此类推)
实际上,您任何时候都没有离开进行上下文切换,解锁后刚好有一个锁。解决方案:交换"lock"和"long empty loop"步骤,这样只有"print"步骤会被锁定,调度程序可以在"long empty loop"期间切换到另一个线程。
欢迎来到话题!
编辑: 专业提示:调试多线程程序很困难。但有时值得插入一个普通的 printf() 来指示锁定和解锁(正确的顺序:锁定,然后是 printf 和 printf,然后是解锁),即使程序看起来是正确的。在这种情况下,您可以看到解锁与锁定之间的间隙为零。
解锁一个互斥体并不能保证另一个正在等待锁定同一个互斥体的线程会立即获得一个锁。
它只保证其他线程会尝试获取锁。
在这种情况下,您在一个线程中解锁互斥体后,同一个线程会立即尝试再次锁定它。即使另一个线程在耐心等待,对于互斥量,也不能保证另一个线程这次会赢。刚刚锁定它的同一个线程可以成功立即再次锁定它。
今天,您看到同一个线程总是赢得锁定竞赛。明天,您可能会发现它始终是另一个线程。无论如何,当有多个线程同时追求同一个互斥锁时,您无法保证哪个线程将获得互斥锁。获胜者取决于您的 CPU 和其他硬件架构、系统加载的繁忙程度、当时以及许多其他因素。
这是一个有效的结果,您的代码不会试图以任何方式控制执行顺序,只要所有线程都在某个时刻执行并且没有问题,它就是一个合法的结果。
即使你切换了循环的顺序和锁(see here), because again you haven't written anything that attempts to control it using e.g conditional variables or just some silly atomic_bool
(这是一个愚蠢的解决方案,只是为了演示你如何真正让它交替并确保它会)布尔值到交替运行。
我是 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 started
Thread2 started
This is function1
This is function2
This is function1
. .
.
.
但是显示的输出如下:
Thread1 started
Thread2 startedThis is function1
This is function1
This is function1
.
.
.
我哪里错了?
您的两个线程都在执行以下步骤:
- 锁定
- 长空循环
- 打印
- 解锁
- 锁定
- 长空循环
- (以此类推)
实际上,您任何时候都没有离开进行上下文切换,解锁后刚好有一个锁。解决方案:交换"lock"和"long empty loop"步骤,这样只有"print"步骤会被锁定,调度程序可以在"long empty loop"期间切换到另一个线程。
欢迎来到话题!
编辑: 专业提示:调试多线程程序很困难。但有时值得插入一个普通的 printf() 来指示锁定和解锁(正确的顺序:锁定,然后是 printf 和 printf,然后是解锁),即使程序看起来是正确的。在这种情况下,您可以看到解锁与锁定之间的间隙为零。
解锁一个互斥体并不能保证另一个正在等待锁定同一个互斥体的线程会立即获得一个锁。
它只保证其他线程会尝试获取锁。
在这种情况下,您在一个线程中解锁互斥体后,同一个线程会立即尝试再次锁定它。即使另一个线程在耐心等待,对于互斥量,也不能保证另一个线程这次会赢。刚刚锁定它的同一个线程可以成功立即再次锁定它。
今天,您看到同一个线程总是赢得锁定竞赛。明天,您可能会发现它始终是另一个线程。无论如何,当有多个线程同时追求同一个互斥锁时,您无法保证哪个线程将获得互斥锁。获胜者取决于您的 CPU 和其他硬件架构、系统加载的繁忙程度、当时以及许多其他因素。
这是一个有效的结果,您的代码不会试图以任何方式控制执行顺序,只要所有线程都在某个时刻执行并且没有问题,它就是一个合法的结果。
即使你切换了循环的顺序和锁(see here), because again you haven't written anything that attempts to control it using e.g conditional variables or just some silly atomic_bool
(这是一个愚蠢的解决方案,只是为了演示你如何真正让它交替并确保它会)布尔值到交替运行。