c++ thread 并发问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Huelse
V2EX    C++

c++ thread 并发问题

  •  
  •   Huelse 2020-07-15 20:39:25 +08:00 3189 次点击
    这是一个创建于 1981 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我想用 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(); } 

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

    这里先感谢各位了!

    18 条回复    2020-08-13 20:42:52 +08:00
    hankai17
        1
    hankai17  
       2020-07-15 20:47:45 +08:00
    thread 不支持 copy?
    Huelse
        2
    Huelse  
    OP
       2020-07-15 21:03:56 +08:00
    @hankai17 #1 是什么意思?
    gantleman
        3
    gantleman  
       2020-07-15 21:07:49 +08:00
    从 C++的语法来说你在 for 循环里声明了两个 thread t1 t2 的局部变量。
    离开 for 循环后这两个局部变量被销毁,任何使用的操作都是非法的。建议你改用 new 尝试下。
    nightwitch
        4
    nightwitch  
       2020-07-15 21:08:11 +08:00   1
    第一个里面,不要用引用去捕获 k 的值,k 的值一直在变,而且当 for 循环结束以后,k 的生命周期结束,你的 lambda 里面的 k 就是空悬引用。
    nightwitch
        5
    nightwitch  
       2020-07-15 21:11:22 +08:00
    @gantleman t1,t2 被 push 到 vector 里面去了啊
    nannanziyu
        6
    nannanziyu  
       2020-07-15 21:17:32 +08:00   1
    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
        7
    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
        8
    nannanziyu  
       2020-07-15 21:23:14 +08:00   1
    然后还有 4 楼说的,你的 k 不能传引用,要传值
    改成
    std::thread t1([&,k]() {
    });
    Huelse
        9
    Huelse  
    OP
       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
        10
    gantleman  
       2020-07-15 21:27:12 +08:00
    @nightwitch 是的,6 楼是正确答案
    GeruzoniAnsasu
        11
    GeruzoniAnsasu  
       2020-07-15 21:29:04 +08:00   2
    c++11 以后不要记得容器有 push_back 这个函数

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

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

    threads.emplace_back([&](){WHATEVER})
    billyzs
        12
    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
        13
    tusj  
       2020-07-16 09:50:16 +08:00
    threads.push_back(std::move(t1));
    Sentan
        14
    Sentan  
       2020-07-16 09:54:34 +08:00
    @nannanziyu 大佬,问下,用 std:move 处理 tread 那个对象,把他变成左值是为了什么,这样是会把这个对象的生命周期变长吗,还是说让他从栈空间变成堆空间了?
    Wirbelwind
        15
    Wirbelwind  
       2020-07-16 10:37:18 +08:00
    @Sentan thread 只有移动语义,所以不能 copy,只能转让所有权,用 std::move 告诉编译器调用移动构造
    Wirbelwind
        16
    Wirbelwind  
       2020-07-16 10:37:48 +08:00   1
    Sentan
        17
    Sentan  
       2020-07-16 15:03:31 +08:00
    @Wirbelwind 哦哦,明白了
    hardwork
        18
    hardwork  
       2020-08-13 20:42:52 +08:00
    你这个和 std::async + future 用法有点像的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     986 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 18:52 PVG 02:52 LAX 10:52 JFK 13:52
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86