C++11 packaged_task未按预期工作 线程退出无输出问题
异常原因
核心错误为std::packaged_task所有权转移的时序错误:
std::packaged_task是仅移动类型,执行thread tpt(move(task), 3, 4);时,主线程中定义的task对象所有权已经被完整转移给子线程的入参,原task对象变为无效空对象,调用其valid()方法会返回false。- 后续主线程在空的
task对象上调用task.get_future(),会直接抛出std::future_error异常,对应错误码为no_state,表示当前packaged_task未关联任何异步共享状态。 - 由于main函数未捕获该异常,栈展开阶段会销毁局部存储的
tpt线程对象,此时tpt仍处于joinable状态(未执行join或detach),std::thread的析构函数检测到该状态会直接调用std::terminate()强制终止程序。 - 输出中能看到
task thread,是因为子线程已经拿到了转移后的有效packaged_task实例,在主线程触发终止流程前刚好执行到lambda内的打印逻辑;后续主线程的join、wait、结果打印等逻辑都因为异常终止完全不会执行,观察到的2秒左右挂起是异常退出流程的调度延迟,不属于正常等待逻辑。
修复方案
调整代码执行顺序,在执行move转移packaged_task所有权之前,先调用get_future()获取关联的future实例,move操作完成后不要再访问原主线程的task对象。另外原代码缺失<thread>头文件(部分编译器会通过其他头文件隐式引入,但不符合C++标准规范,需要补上)。
修复后完整代码:
#include<future> #include<iostream> #include<thread> using namespace std; int main() { cout << "---------" << endl; packaged_task<int(int, int)> task([](int a, int b){ cout << "task thread\n"; return a + b; }); // 先获取关联的future,再转移task所有权 future<int> sum = task.get_future(); thread tpt(move(task), 3, 4); cout << "after thread creation\n"; cout << "before join\n"; tpt.join(); cout << "after join\n"; sum.wait(); // 该逻辑冗余:后续sum.get()本身会阻塞等待结果就绪,删除不影响运行结果 cout << "after wait\n"; cout << sum.get() << endl; return 0; }
修复后程序可正常运行,典型输出如下(task thread的打印位置可能因线程调度顺序略有浮动,属于正常现象):
--------- after thread creation before join task thread after join after wait 7
内容的提问来源于stack exchange,提问作者gongliming7
相关产品推荐
相关产品推荐

