Erm*_*ndo 19 c++ multithreading
我试图理解 C++ 中的多线程,但我遇到了这个问题:如果我在for循环中启动线程,它们会打印错误的值。这是代码:
#include <iostream>
#include <list>
#include <thread>
void print_id(int id){
printf("Hello from thread %d\n", id);
}
int main() {
int n=5;
std::list<std::thread> threads={};
for(int i=0; i<n; i++ ){
threads.emplace_back(std::thread([&](){ print_id(i); }));
}
for(auto& t: threads){
t.join();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我期待打印值 0,1,2,3,4 但我经常得到两次相同的值。这是输出:
Hello from thread 2
Hello from thread 3
Hello from thread 3
Hello from thread 4
Hello from thread 5
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
Bat*_*eba 18
该[&]语法是导致i被捕获作为参考。因此,i当线程运行时,通常会比您预期的更先进。更严重的是,如果在线程运行之前超出范围,则代码的行为是未定义的i。
i按值捕获- 即std::thread([i](){ print_id(i); })是修复。
两个问题:
您无法控制线程何时运行,这意味着ilambda 中变量的值可能不是您所期望的。
该变量i对于循环和仅循环是局部的。如果循环在一个或多个线程运行之前完成,则这些线程将对生命周期已结束的变量进行无效引用。
您可以通过i 按值而不是按引用捕获变量来非常简单地解决这两个问题。这意味着每个线程都将拥有该值的副本,并且该副本将为每个线程创建唯一的副本。
另一件事:
不要等到总是有一个有序的序列: 0, 1, 2, 3, ... 因为多线程执行模式有一个特殊性:indeterminism。
不确定性意味着在相同的条件下执行相同的程序会产生不同的结果。
这是因为操作系统根据以下几个参数对不同执行的线程进行调度:CPU 负载、其他进程的优先级、可能的系统中断等。
您的示例仅包含五个线程,因此很简单。尝试增加线程数,例如在处理函数中休眠。您将看到结果可能因一次执行而异。