Linux下多线程编程与信号处理易疏忽的一个例子
作者 佚名技术
来源 Linux系统
浏览
发布时间 2012-05-11
这几天把一个网络流量采集器程序基本改好了,原来在main函数中把几个子线程启动后就睡10分钟后开始清理子线程后退出.现在想改成子线程启动后主线程进入无限睡眠,直到收到SIGTERM或SIGINT.主程序如下: 其他头文件 #include <signal.h> //信号处理所需要的头文件 int main(int argc, char * argv[]){ //其他所需要的变量声明 sigset_t sig_set,sig_pending; // 设置信号阻塞 sigemptyset(&sig_set); sigaddset(&sig_set,SIGTERM); sigaddset(&sig_set,SIGINT); sigprocmask(SIG_BLOCK,&sig_set,NULL); 启动几个子线程 ........... // 设置信号阻塞 sigemptyset(&sig_set); sigaddset(&sig_set,SIGTERM); sigaddset(&sig_set,SIGINT); sigprocmask(SIG_BLOCK,&sig_set,NULL); //主线程进入睡眠,等待信号到达后跳出睡眠 while(1){ sigpending(&sig_pending); if(sigismember(&sig_pending, SIGTERM)|| sigismember(&sig_pending,SIGINT)){ break; } sleep(2); } //子线程退出情理 ................ return 0; } 程序运行后发现 当按下Ctrl C后程序没有出现子线程退出时的信息而是立刻退出,非常奇怪. 仔细分析了一下,发现问题在于忽略了Linux下的多线程模型的特点. Linux下的线程实质上是轻量级进程(light weighted process),线程生成时会生成对应的进程控制结构,只是该结构与父线程的进程控制结构共享了同一个进程内存空间. 同时新线程的进程控制结构将从父线程(进程)处复制得到同样的进程信息,如打开文件列表和信号阻塞掩码等.我们是在子线程生成之后修改了信号阻塞掩码,此刻子线程使用的是主线程原有的进程信息,因此子线程仍然会对SIGINT和SIGTERM信号进行反应,因此当我们用Ctrl C发出了SIGINT信号的时候,主进程不处理该信号,而子进程(线程)会进行默认处理,即退出.子进程退出的同时会向父进程(线程)发送SIGCHLD信号,表示子进程退出,该信号没有被阻塞,因此会导致主进程(线程)也立刻退出,出现了前述的运行情况.因而该问题的一个解决方法是在子线程生成前进行信号设置, 或在子线程内部进行信号设置. 子线程是往往是一个事务处理函数,因此我建议在简单的情况下采用前者,如果需要处理的信号比较复杂,那就使用后一种方法来处理.这样,以上的程序逻辑改为如下就可以了:
#include <signal.h> //信号处理所需要的头文件 int main(int argc, char * argv[]){ //其他所需要的变量声明 sigset_t sig_set,sig_pending; 启动几个子线程 ........... //主线程进入睡眠,等待信号到达后跳出睡眠 while(1){ sigpending(&sig_pending); if(sigismember(&sig_pending, SIGTERM)|| sigismember(&sig_pending,SIGINT)){ break; } sleep(2); } //子线程退出情理 ................ return 0; }
|
||
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |
你可能对下面的文章感兴趣
上一篇: 利用Linux系统命令行性能检测工具下一篇: 可扩展、高可用、负载均衡网站架构设计方案
关于Linux下多线程编程与信号处理易疏忽的一个例子的所有评论