printf()作为安全取消点的机制及线程取消相关问题咨询
线程取消与printf、time命令的疑问
测试代码
#include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <unistd.h> void *thread_function(void *arg) { while(1) { printf("hello\n"); //sleep(1); } return NULL; } int main() { pthread_t thread; if(pthread_create(&thread, NULL, thread_function, NULL) != 0) { perror("Failed to create a thread"); return -1; } printf("After sleep in main thread\n"); if (pthread_cancel(thread) != 0) { perror("Failed to cancel thread"); return EXIT_FAILURE; } pthread_join(thread, NULL); printf("Thread is cancelled\n"); }
疑问点
- 当线程函数中用
sleep()时,线程能立即被取消;但用printf()时,取消线程需要耗时。已知sleep()是安全取消点,printf()可能是安全取消点,想知道printf()在运行的哪个阶段会成为取消点并触发线程取消? - 用
time命令运行程序时,显示的运行时长为2秒,但实际感觉运行时间更长,这是为什么?
问题解答
1. printf()何时成为取消点触发线程取消
printf()本身不是POSIX标准强制规定的取消点,但它内部调用的底层I/O函数(比如write())是标准定义的安全取消点。只有当printf()触发缓冲区刷新、调用到底层系统调用时,才会触发取消检查:
- 比如默认行缓冲模式下,输出换行符
\n会触发缓冲刷新;或者缓冲区被填满达到阈值时,printf()会调用write()向内核写入数据。此时write()作为取消点,会检查线程是否存在未处理的取消请求,一旦检测到就会终止线程。 - 如果缓冲区没满,
printf()只是把数据写入用户态缓冲区,不会进入系统调用,也就不会触发取消检查。线程会继续循环执行printf,直到某次操作触发缓冲刷新、调用到底层系统调用时,才会响应取消请求——这就是用printf时取消线程需要耗时的原因。
2. time命令显示时长与实际感觉不符的原因
time命令统计的是进程的CPU时间(包括用户态CPU时间和内核态CPU时间),而不是你主观感受到的墙上时钟时间(实际流逝的时间):
- 当线程疯狂调用
printf时,大部分时间要么在用户态填充缓冲区,要么等待内核处理I/O(此时进程会进入睡眠状态,不占用CPU)。time只统计进程实际占用CPU的时间,而你感受到的是从程序启动到结束的完整时间,其中包含了进程等待I/O、被调度器切换出去的时间。 - 另外,大量的
printf输出会让终端I/O成为瓶颈,进程会频繁陷入睡眠等待终端接收数据,这部分等待时间不会被计入time的CPU时间统计,但会让你觉得程序运行了更久。
内容的提问来源于stack exchange,提问作者Мария Шипаева
相关产品推荐
相关产品推荐

