理解C++栈对象分配规则及线程传递移动对象后崩溃问题
问题根因分析
崩溃的直接原因是对std::thread对象执行了错误的操作流程:
- 你先调用了
thd.detach(),这会将线程的执行权完全交给操作系统,同时当前std::thread对象会和实际执行的线程解除关联,变为*不可联接(joinable)*状态 - 之后你又把已经detach的线程对象存入vector,最后遍历vector调用
join(),对不可联接的线程执行join操作,C++标准明确规定会抛出std::system_error异常,对应你看到的Invalid argument错误。
代码修复方案
你只需要删掉thd.detach()这一行即可,修改后的循环逻辑如下:
for (int i = 0; i < 5; i++) { std::cout << "loop iteration " << i << std::endl; thing t(i); // 直接构造线程,不需要detach std::thread thd(std::bind(handle_thing, i, std::move(t))); // 直接存入vector即可 threads.push_back(std::move(thd)); }
你的栈对象移动传递逻辑本身是完全正确的:std::move将栈上的thing对象转移到std::bind的绑定对象中,再转移到std::thread的内部存储,全程没有悬垂引用,符合你要传递不可拷贝对象的需求。
针对socket传递场景的补充说明
对于不可拷贝的boost::ip::tcp::socket对象,你现在的写法思路完全可用:
- 循环内栈上构造socket对象
- 用
std::move将socket转移给线程的入口函数,整个过程没有拷贝,只有移动操作,效率很高 - 不需要调用detach,统一将线程存入vector后join即可;如果不需要等待线程返回才退出主程序,才需要用detach,这种情况就不要再把线程对象存入vector执行join,两种操作二选一即可。
内容的提问来源于stack exchange,提问作者Ihab Awad
相关产品推荐
相关产品推荐

