您的位置:首页 > 其它

进程线程中睡眠函数(sleep)被信号中断后失效,处理方式总结

2016-08-16 22:59 1896 查看
进程线程中睡眠函数sleep被信号中断后失效,处理方式

很多时候根据程序运行需要,或者调试什么的,需要在程序中延时。当然一般应用的是sleep 函数 , 但是有些时候,如果不注意sleep的用法,那么在多线程编程中,在信号驱使下sleep就会出现失效的特性,或者说起不到延时的作用,原因何在,先看一段代码:

#include
#include
#include
#include

#include
#include

void tid1_handler(void *arg);
void tid1_SIGINT_fun(int signo);
void tid1_SIGQUIT_fun(int signo);
void tid2_handler(void *arg);
void tid2_SIGUSR2_fun(int signo);
pthread_t tid1 , tid2; //创建全局的子线程标识
int main(void){

//信号处理,先屏蔽所有的信号
//定义一个信号的集合
sigset_t sig_sets;
//置空信号集合
sigemptyset(&sig_sets);
//装填所有的信号
sigfillset(&sig_sets);
//开始屏蔽
//sigprocmask(SIG_BLOCK , &sig_sets , NULL);
pthread_sigmask(SIG_BLOCK , &sig_sets , NULL);
//---所有信号屏蔽完成

//创建两个子线程并设置处理函数
pthread_create(&tid1 , NULL , (void *)tid1_handler , NULL);
pthread_create(&tid2 , NULL , (void *)tid2_handler , NULL);

//while(1);
pthread_join(tid1 , NULL);
pthread_join(tid2 , NULL);

printf("主线程开始退出啦 ....\n");

return 0;
}

void tid1_handler(void *arg){
//pthread_detach(tid1);
//子线程1处理函数  且对 SIGINT 信号开放
//定义一个信号的集合
sigset_t set1;
//置空信号集合
sigemptyset(&set1);
//装填信号
sigaddset(&set1 , SIGINT);
sigaddset(&set1 , SIGQUIT);
//安装信号
signal(SIGINT , tid1_SIGINT_fun);
signal(SIGQUIT , tid1_SIGQUIT_fun);
//放开屏蔽的信号
//int sig  = 0;
//sigwait(&set1 , &sig);
//printf("sig = %d \n",sig);
pthread_sigmask(SIG_UNBLOCK , &set1 , NULL);
//重新发送可能被屏蔽的信号
int ret = -1;
ret = sigpending(&set1);
if(ret < 0){
perror("sigpending");
exit(1);
}
int i = 0;
while(1){

printf("tid1 is running [%3d]\n" , i++);
sleep(1);
}

}

void tid1_SIGINT_fun(int signo){
//信号执行
if(SIGINT == signo){
printf("                     tid1 --->receive a SIGINT signal\n");
pthread_kill(tid2 , SIGUSR2);
}
}

void tid1_SIGQUIT_fun(int signo){
//信号执行
if(SIGQUIT ==signo){
printf("                     tid1 --->receive a SIGQUIT signal\n");
exit(1);
}

}

void tid2_handler(void *arg){

//pthread_detach(tid2);

//子线程2处理函数
//定义一个信号集合
sigset_t set2;
//置空信号集合
sigemptyset(&set2);
//装填信号
sigaddset(&set2 , SIGUSR2);
//安装信号
signal(SIGUSR2 , tid2_SIGUSR2_fun);
//放开屏蔽的信号
pthread_sigmask(SIG_UNBLOCK , &set2 , NULL);
//重新发送可能被屏蔽的信号
sigpending(&set2);
#if 1
int i = 30;
while(i--){
sleep(1);
}
#else
sleep(30);
#endif
pthread_exit(NULL);

}

void tid2_SIGUSR2_fun(int signo){

//信号执行
if(SIGUSR2 == signo){
printf("                     tid2 --->receive a SIGUSR2 signal \n");
}
}


在这段代码中我们可以看到113行if后如果为0 那么程序就会执行 sleep(30),然而程序在真正执行的时候,除非你不进行任何的操作,就等着程序运行结束,你可以看到正常现象。如果你在程序运行期间发送一个SIGINT信号(且在程序运行开始30之内)那么你就会看到,程序直接结束了tid2的线程,sleep并没卵用。
         那么是为何呢?
         就是因为sleep()运行是程序捕获到一个信号,那么这个信号就会中断sleep,去执行信号所指内容,等处理好信号之后,程序会直接跳到sleep的下一行执行,那么即使sleep秒数没有数完,也照样结束。这就是造成sleep失效的原因。
那么根据这个特性,我提供一种不太精确的解决方法,就是将sleep放到一个循环中去。每次循环延时1秒,因此要延时的秒数约等于循环的次数。在延时精度要求不高的情况下我认为这个方法是可行的,也希望我的方法能够抛砖引玉,得到更多好的方法;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: