c++ thread 并发问题

2020-07-15 20:39:25 +08:00
 Huelse

我想用 thread 并发处理 for 循环,但总是 join 放在循环外就会出错,是 lambda 的问题吗?

vector<thread> threads;

for (int k = 1; k < d; k++)
{
    thread t1([&](){
        A_result[k] = Linear_Transform_Plain(A_result[0], params);
    });
    thread t2([&](){
        B_result[k] = Linear_Transform_Plain(B_result[0], params);
    });
    threads.push_back(t1);
    threads.push_back(t2);
    // join 在里面就不会出错
    // t1.join();
    // t2.join();
}
for(auto i = threads.begin(); i != threads.end(); i++){
    i->join();
}

报错:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

尝试过换用thread threads[14]然后索引赋值的方法,报错:

terminate called recursively
Aborted (core dumped)

然后不用 lambda 就可以运行,但获取不到返回值了

thread threads[14];

for (int k = 1; k < d; k++)
{
    threads[k-1] = thread(Linear_Transform_Plain, A_result[0], params);
    threads[k-1+7] = thread(Linear_Transform_Plain, B_result[0], params);
}
for (int k = 1; k < d; k++)
{
    threads[k-1].join();
    threads[k-1+7].join();
}

网上找了大多是基础用法和线程池,并不能达到我想要的全核心并发处理。

这里先感谢各位了!

2672 次点击
所在节点    C++
18 条回复
hankai17
2020-07-15 20:47:45 +08:00
thread 不支持 copy?
Huelse
2020-07-15 21:03:56 +08:00
@hankai17 #1 是什么意思?
gantleman
2020-07-15 21:07:49 +08:00
从 C++的语法来说你在 for 循环里声明了两个 thread t1 t2 的局部变量。
离开 for 循环后这两个局部变量被销毁,任何使用的操作都是非法的。
建议你改用 new 尝试下。
nightwitch
2020-07-15 21:08:11 +08:00
第一个里面,不要用引用去捕获 k 的值,k 的值一直在变,而且当 for 循环结束以后,k 的生命周期结束,你的 lambda 里面的 k 就是空悬引用。
nightwitch
2020-07-15 21:11:22 +08:00
@gantleman t1,t2 被 push 到 vector 里面去了啊
nannanziyu
2020-07-15 21:17:32 +08:00
std::thread 没有拷贝构造函数

http://www.cplusplus.com/reference/thread/thread/thread/
3) copy constructor
Deleted constructor form (thread objects cannot be copied).

所以修改 threads.push_back(t1); 为 threads.push_back(std::move(t1))
V2WT
2020-07-15 21:20:44 +08:00
```
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
int main()
{
// vector container stores threads
std::vector<std::thread> workers;
for (int i = 0; i < 5; i++) {
workers.push_back(std::thread([]()
{
std::cout << "thread function\n";
}));
}
std::cout << "main thread\n";

// Looping every thread via for_each
// The 3rd argument assigns a task
// It tells the compiler we're using lambda ([])
// The lambda function takes its argument as a reference to a thread, t
// Then, joins one by one, and this works like barrier
std::for_each(workers.begin(), workers.end(), [](std::thread &t)
{
t.join();
});

return 0;
}

```
I found these code, from here:
[click]( https://www.bogotobogo.com/cplusplus/C11/3_C11_Threading_Lambda_Functions.php).
Hope this would help!
nannanziyu
2020-07-15 21:23:14 +08:00
然后还有 4 楼说的,你的 k 不能传引用,要传值
改成
std::thread t1([&,k]() {
});
Huelse
2020-07-15 21:23:38 +08:00
@nannanziyu #6
@nightwitch #4
感谢感谢~
综合两位的答案,将第一个例子改成
```
std::thread t1([&, k](){
A_result[k] = ...
});

threads.push_back(std::move(t1));
```
就可以了,核心跑满,舒服了~
gantleman
2020-07-15 21:27:12 +08:00
@nightwitch 是的,6 楼是正确答案
GeruzoniAnsasu
2020-07-15 21:29:04 +08:00
c++11 以后不要记得容器有 push_back 这个函数

一律用 emplace_back,这个函数会自动转发左右值引用

emplace_back 还有一个重载是用入参构造元素,所以可以

threads.emplace_back([&](){WHATEVER})
billyzs
2020-07-16 01:34:49 +08:00
@GeruzoniAnsasu 这个例子直接上 emplace_back()没问题,不过明确需要拷贝左值的时候 push_back()可读性更高
[https://abseil.io/tips/112]( https://abseil.io/tips/112)
tusj
2020-07-16 09:50:16 +08:00
threads.push_back(std::move(t1));
Sentan
2020-07-16 09:54:34 +08:00
@nannanziyu 大佬,问下,用 std:move 处理 tread 那个对象,把他变成左值是为了什么,这样是会把这个对象的生命周期变长吗,还是说让他从栈空间变成堆空间了?
Wirbelwind
2020-07-16 10:37:18 +08:00
@Sentan thread 只有移动语义,所以不能 copy,只能转让所有权,用 std::move 告诉编译器调用移动构造
Wirbelwind
2020-07-16 10:37:48 +08:00
Sentan
2020-07-16 15:03:31 +08:00
@Wirbelwind 哦哦,明白了
hardwork
2020-08-13 20:42:52 +08:00
你这个和 std::async + future 用法有点像的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/690371

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX