c++ - 在 C++ 中将线程存储在向量中
问题描述
我正在学习并行编程,我的讲座中有一个例子。我们有一个用于存储 20 个斐波那契数的数组,基本上,为了计算每个数,创建了一个线程。这是斐波那契函数的代码:
unsigned int fibonacci(unsigned int n) {
if(n==0)
return 0;
unsigned int f0 = 0, f1 = 1, f2;
for (auto i=1u; i < n; i++) {
f2 = f0 + f1;
f0 = f1;
f1 = f2;
}
return f1;
}
这是主要方法的代码:
int main(int argc, char **argv) {
std::vector<std::thread> threads;
unsigned int results[20];
for(auto i=0u; i < 20; i++) {
auto f = rand() % 30;
threads.push_back(std::thread([&](){
results[i] = fibonacci(f);
}));
}
std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
for(auto& r: results) {
std::cout << r << " ";
}
std::cout << std::endl;
return 0;
}
计算了数字,但程序以状态-1073741819 (0xC0000005)终止。我关注了这篇文章,但即使应用emplace.back()
也没有任何变化。那么这个错误的原因可能是什么?
解决方案
您的问题是范围(还有其他问题):
for(auto i=0u; i < 20; i++) {
// This value is reinitialized every loop.
// Though it is likely that every loop will use the same
// physical memory location for f this is not guaranteed by
// the standard (especially if the loop is unrolled)
auto f = rand() % 30;
// Here you are capturing i, f, results by reference.
// Because they are captured by reference your main
// thread and the created thread are both referencing the same object.
//
// One thread is modifying i, f the other is reading these value.
// There is no attempt to make sure that the objects are accessed
// between memory barriers (I am not sure what the modern terms are
// thus you don't know what values you will be getting).
threads.push_back(std::thread([&](){
results[i] = fibonacci(f);
}));
}
// At this point both the variable f and the variable i are out of scope.
// technically they do not exist and thus the references captured by
// the threads point to memory locations with a non live object.
//
// These locations are more than likely being used for other variables.
//
// If one of the threads accesses these memory locations after the main
// thread reaches this point then you have undefined behavior.
有几个解决方案。
按值传递 i, f
如果您为线程提供自己的副本,i
那么f
您将不会遇到共享访问或访问生命周期已结束的对象的问题。
// still need to capture results by reference.
threads.push_back(std::thread([i, f, &results](){
results[i] = fibonacci(f);
}));
保留所有值f
并传递对这些值的引用。
unsigned int results[20];
// have an array of f one value for each thread.
int f[20];
for(auto i=0u; i < 20; i++) {
// Assign the random to the correct location in f.
f[i] = rand() % 30;
// Pass references f[i] and results[i]
// Once the reference has been captured the value of i
// is no longer needed.
threads.push_back(std::thread([&f = f[i], &result = results[i]](){
result = fibonacci(f);
}));
}
推荐阅读
- xamarin - Xamarin 表单应用无法部署到 Android 10 真机
- mysql - 将特殊字符插入mysql数据库
- angular - Angular 库 PROD 构建引发异常
- android - ViewModel 对象差异
- java - Scheduler.triggerJob 不触发作业
- php - 在 PHP 中替换 UTF-8 KeyCap 数字字符
- flutter - 无法将颤振添加到我的路径变量中。我在 mac OS catalina 上使用 ohmyzsh
- python - 如何将scapy对象转换为字符串
- c# - 在 While 循环中为动态变量赋值
- python - 有没有办法在 Jupyter Notebook 上隐藏部分代码?