[英]Why is the for loop and the hard coded yielding different results?
I have created a program in C++ that doesn't work when the thread vectors' components are created with a for loop and does when they are created hard coded.我在 C++ 中创建了一个程序,该程序在使用 for 循环创建线程向量组件时不起作用,并且在创建硬编码时起作用。 This is the hard coded example:
这是硬编码示例:
std::vector<std::thread> ThreadVector;
ThreadVector.emplace_back(std::move(std::thread([&](){cl.run(maxLast, vals[0], 0);})));
ThreadVector.emplace_back(std::move(std::thread([&](){cl.run(maxLast, vals[1],1);})));
ThreadVector.emplace_back(std::move(std::thread([&](){cl.run(maxLast, vals[2],2);})));
ThreadVector.emplace_back(std::move(std::thread([&](){cl.run(maxLast, vals[3],3);})));
ThreadVector.emplace_back(std::move(std::thread([&](){cl.run(maxLast, vals[4],4);})));
for(auto& t:ThreadVector)
t.join();
maxLast
is an integer that is the value of the double char array. maxLast
是一个 integer,它是双字符数组的值。 the vals
variable is a tripple char array, think a vector of strings within a vector. vals
变量是一个三元字符数组,可以考虑一个向量中的字符串向量。 and the last value is a number to send through the function.最后一个值是通过 function 发送的数字。 The cl.run function basically just takes an array of char arrays, writes to a file the maxLast variable then on the next line the next string from the array.
cl.run function 基本上只需要一个字符数组 arrays,将 maxLast 变量写入文件,然后在下一行写入数组中的下一个字符串。 The name of the file is called
trying
then the added number then .txt
the function is shown below:文件名叫做
trying
,然后加上数字,然后.txt
function如下所示:
void dir::run(int nums, char *vals[nums], int count){
std::cout<<"got started "<<nums<<" "<<count<<std::endl;
std::string filestr = "trying"+std::to_string(count)+".txt";
for(int i = 0; i < nums; i++){
writeLine(std::to_string(nums), filestr);
writeLine(std::string(vals[i]), filestr);
}
}
void dir::writeLine(std::string w, std::string p){
FILE* stream = fopen(p.c_str(), "a+");
fputs(w.c_str(), stream);
fputs("\n", stream);
fclose(stream);
}
When the hardcoded into the ThreadVector
variable as shown above is run, it works perfectly.当硬编码到如上所示的
ThreadVector
变量中运行时,它可以完美运行。 However, if I were to run it the following way, there would be a file called trying5.txt
there would also be strings I never had put into the char array printed onto the file.但是,如果我按以下方式运行它,将会有一个名为
trying5.txt
的文件,还会有我从未放入打印到文件上的 char 数组中的字符串。 There would also be some threads that received the same i
value.也会有一些线程收到相同的
i
值。
int i;
int ques=5;
for(i = 0; i < ques; i++){
printf("running %d\n", i);
ThreadVector.emplace_back(std::move(std::thread([&](){cl.run(maxLast, vals[i],i);})));
}
for(auto& t:ThreadVector)
t.join();
which prints on one of the runs into the terminal (cleaned up a bit):在其中一个运行中打印到终端(清理了一下):
running 0
running 1
running 2
running 3
running 4
got started 30 2
got started 30 2
got started 30 4
got started 30 3
got started 30 4
Which is obviously not what is supposed to happen, and as mentioned sometimes the terminal would print got started 30 5
and I would end up with a file named trying5.txt
.这显然不是应该发生的,正如提到的,有时终端会打印
got started 30 5
,我最终会得到一个名为trying5.txt
的文件。 I have also tried push_back
instead of emplace_back
.我也尝试过
push_back
而不是emplace_back
。
std::thread([&]
[&]
means that all objects captured by the closure get captured by reference . [&]
表示闭包捕获的所有对象都被引用捕获。
cl.run(maxLast, vals[i],i)
i
was captured by reference. i
被引用捕获了。 i
was the parent execution thread's loop variable, that gets incremented on every iteration of the loop. i
是父执行线程的循环变量,在循环的每次迭代中都会递增。
C++ gives you no guarantees, whatsoever, when each execution thread executes anything, in relation to anything in the parent execution thread, unless explicit synchronization takes place. C++ 不保证每个执行线程何时执行与父执行线程中的任何内容相关的任何内容,除非发生显式同步。
No such synchronization occurs here.这里没有发生这样的同步。 The parent execution thread might've already incremented
i
by the time the new execution thread evaluates this val[i]
, as well as the discrete i
parameter to the function call;当新的执行线程评估这个
val[i]
以及 function 调用的离散i
参数时,父执行线程可能已经增加了i
; it already ended the current iteration of the loop and moved to the next one.它已经结束了循环的当前迭代并移至下一个迭代。 Or even iterated several times.
甚至多次迭代。 Or the loop may be completely over in the parent execution thread, and
i
is now at its final value.或者循环可能在父执行线程中完全结束,并且
i
现在处于其最终值。
got started 30 2
got started 30 2
got started 30 4
got started 30 3
got started 30 4
You see exactly this result, here.你在这里看到了这个结果。 Each execution thread gets around to evaluating its
i
after the parent execution thread iterated, and incremented i
, an unpredictable number of times.在父执行线程迭代并递增
i
后,每个执行线程都开始评估其i
,次数不可预测。 Some of the new execution threads even managed to evaluate i
at the same time, resulting in the same observed value of i
.一些新的执行线程甚至设法同时评估
i
,从而得到相同的i
观察值。
This is what capturing objects "by reference means".这就是“通过引用方式”捕获对象的方式。 Use
[=]
to capture by value instead.改为使用
[=]
按值捕获。 This means that each execution thread sees the value of each captured object at the time the execution thread was created.这意味着每个执行线程在创建执行线程时看到每个捕获的 object 的值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.