为何WSL2中运行该C++多线程程序会重复打印'thread 1 exists'?
WSL2下C++多线程printf重复输出问题分析与解决
问题现象
运行以下C++多线程程序时,thread 1 exists被重复打印两次,不符合每个线程仅输出一次退出信息的预期。
程序代码
#include <atomic> #include <condition_variable> #include <cstdio> #include <cstdlib> #include <memory> #include <mutex> #include <shared_mutex> #include <thread> #include <iostream> #include <future> std::atomic<int> g_Flag = 0; std::atomic<int> cnt = 0; void worker1(std::future<int> fut) { printf("this is thread 1\n"); g_Flag = 1; cnt++; fut.get(); printf("thread 1 exists\n"); } void worker2(std::promise<int> prom) { printf("this is thread 2\n"); g_Flag = 2; cnt++; prom.set_value(10); printf("thread 2 exists\n"); } using namespace std::chrono_literals; int main() { std::promise<int> prom; std::future<int> fut = prom.get_future(); std::thread t1(worker1, std::move(fut)); std::thread t2(worker2, std::move(prom)); while (cnt.load() != 2) { } t1.detach(); t2.detach(); printf("main exists\n"); return 0; }
实际输出
eugene@DESKTOP-P8P395D:~/tron$ ./a.out this is thread 1 this is thread 2 main exists thread 2 exists thread 1 exists thread 1 exists
原因分析
这个问题并非WSL2环境本身的问题,而是程序同步逻辑存在缺陷,触发了未定义行为:
- 主线程的
while (cnt.load() != 2)仅能确认两个线程执行到了cnt++的位置,但无法保证线程已经完成后续的printf操作。 - 主线程调用
detach后立即return 0,进程会触发终止流程。此时操作系统会强制终止所有仍在运行的分离线程,如果子线程正处于printf的IO操作过程中,stdio缓冲区的异常处理会导致重复输出这类未定义行为。
解决方向
替换detach为join(推荐):
这是最安全的方案,主线程等待所有子线程完全执行完毕后再退出,从根本上避免进程提前终止导致的子线程IO异常。修改main函数:int main() { std::promise<int> prom; std::future<int> fut = prom.get_future(); std::thread t1(worker1, std::move(fut)); std::thread t2(worker2, std::move(prom)); // 等待子线程执行完成 t1.join(); t2.join(); printf("main exists\n"); return 0; }完善同步机制(若必须使用detach):
添加额外的同步变量(比如std::atomic<int>),让主线程等待所有子线程完成所有操作后再退出,而不是仅等待cnt==2。例如:- 添加全局变量
std::atomic<int> done_cnt = 0; - 在每个线程的最后一行添加
done_cnt++; - 主线程替换等待逻辑为
while (done_cnt.load() != 2) {},确保子线程完全执行完毕后再detach并退出。
- 添加全局变量
内容的提问来源于stack exchange,提问作者Eadren King
相关产品推荐
相关产品推荐

