C++中取消线程后cout进入错误状态的原因探究
问题代码
#include <iostream> #include <pthread.h> #include <assert.h> #include <unistd.h> #include <signal.h> using namespace std; void *func_1 (void *arg) { for (;;) { cout << "1" << endl; sleep (1); } return NULL; } void *func_2 (void *arg) { for (;;) { cout << "222" << endl ; sleep (1); } return NULL; } int main (void) { pthread_t thread_1, thread_2; assert (pthread_create (&thread_1, NULL, func_1, NULL) == 0); assert (pthread_create (&thread_2, NULL, func_2, NULL) == 0); pthread_cancel (thread_1); pthread_join (thread_1, NULL); pthread_join (thread_2, NULL); }
程序输出
1 222
问题描述
程序输出上述内容后进入阻塞状态,此时cout.bad()和cout.fail()均返回true;改用printf()则运行正常,调用cout.clear()后程序可恢复正常。需要解释为何cout会进入错误状态。
原因分析
线程取消打断IO操作
当主线程调用pthread_cancel(thread_1)时,thread_1可能正处于cout << "1" << endl;的执行过程中——endl会触发标准输出流的缓冲区刷新操作,这个操作涉及内核级系统调用(将缓冲区数据写入终端)。而IO操作属于POSIX定义的线程取消点,线程会在这个点响应取消请求,直接终止执行。C++流的状态被异常置位
C标准输出流cout内部维护了状态标志位(如badbit、failbit),用于标识流操作的健康状态。当线程在IO系统调用过程中被强制终止时,未完成的IO操作会被判定为失败,C标准库会自动将cout的badbit和failbit置为true,标记流处于错误状态,后续所有流操作都会直接失败,导致thread_2的cout输出被抑制,程序表现为阻塞。printf不受影响的原因
C标准库的printf函数实现逻辑与C++流不同:对于被中断的系统调用,C标准库通常会尝试自动重启系统调用(若对应信号为可重启类型),或者不会将中断关联到流的错误状态上,因此printf可以继续正常输出。cout.clear()恢复的原理
cout.clear()函数的作用是重置流的所有错误状态标志位,将badbit、failbit等恢复为false,让cout重新回到可操作状态,后续的流操作即可正常执行。
内容的提问来源于stack exchange,提问作者sixsixqaq

