linux -多线程通信(二)信号的处理

信号的处理

int pthread_kill(pthread_t thread, int sig);
发送信号
如果sig是0,则无信号发送,但可以用来检测线程是否还活着。SIGQUIT是终止。

返回值:
   ESRCH 线程已结束
   EINVAL 线程还存在

  • int sigaction(int signum, const struct sigaction act, struct sigaction oldact);
    给信号sig设置一个处理函数,处理函数再sigaction中指定。类似进程中的signal
    act.sa_mask    信号屏蔽字
    act.sa_handler   信号集处理程序。
    参数:signum,信号的名字
       act,传入新的处理方式,指针非空, 则修改信号的动作;
       oldact,传出旧的处理方式,指针非空, 则返回该信号的上一个动作.
    返回值:成功返回0,失败返回错误码
    struct sigaction {
              void (*sa_handler)(int);
              void (*sa_sigaction)(int, siginfo_t *, void *);
              sigset_t sa_mask;
              int sa_flags;
              void (*sa_restorer)(void);
            }
            
    sa_handler:指定信号捕捉后的处理函数名,也可以赋值为SIG_IGN表示忽略或SIG_DFT表示执行默认操作
    sa_mask:调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。
     注意:仅在处理函数被调用期间屏蔽生效,是临时性设置。用sigaddset函数添加需要被捕捉的信号。
    sa_flags:通常设置为0,表示使用默认属性,为0的时候,可以屏蔽正在处理的信号(若在处理二号信号的时候又有二号信号,则此时传来的二号信号就会被屏蔽)
    使用:

  • int sigenptyset(sigset_t set);
    -清空信号集

  • int sigfillset(sigset_t set);
    -将所有信号加入信号集

  • int sigaddset(sigset_t set, int signum);
    -增加一个信号到信号集

  • int sigdelset(sigset_t set,int signum);
    -删除一个信号到信号集

void sig_handler1(int arg)
{
	printf("thread1 get signal\n");
	return;
}
void *thread_fun1(void *arg)
{
	/* 
	   1.定义act结构体
	   2. 添加SIGQUIT信号到屏蔽信号集,将SIGQUIT	屏蔽
	   3.将SIGQUIT以新函数代替
	  ( 需要设置act里的屏蔽信号集和处理信号)
	*/
	struct sigaction act;
	memset(&act,0,sizeof(act));
	sigaddset(&act.as_mask,SIGQUIT); //添加SIGQUIT信号到屏蔽信号集
	act.sa_handler = sig_handler1;//指定信号捕捉后的处理函数名
	sigaction(SIGQUIT, &act,NULL); //将SIGQUIT信号 以act
	
}

多线程信号屏蔽处理。
int pthread_sigmask(int how,const sigset_t *set, sigset_t *oldset)
how=SIG_BLOCK :向当前的信号掩码中添加set,其中set表示要阻塞的信号组
SIG_BLOCK 删除set
SIG-SETMASK 替换为set

实例

#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "signal.h"
#include "string.h"
#include "unistd.h"
void sig_handler1(int arg)
{
	printf("thread1 get signal\n");
	return;
}

void sig_handler2(int arg)
{
	printf("thread2 get signal\n");
	return;
}

void *thread_fun1(void *arg)
{
	printf("new thread 1\n");
	struct sigaction act;
	memset(&act,0,sizeof(act));
	sigaddset(&act.sa_mask,SIGQUIT);
	act.sa_handler = sig_handler1;
	sigaction(SIGQUIT, &act,NULL);
	pthread_sigmask(SIG_BLOCK,&act.sa_mask,NULL);//删除添加的屏蔽信号组sa_mask
	sleep(2);
}

void *thread_fun2(void *arg)
{
	printf("new thread 2\n");
	struct sigaction act;
	memset(&act,0,sizeof(act));
	
	sigaddset(&act.sa_mask,SIGQUIT);
	act.sa_handler = sig_handler2;
        
	sigaction(SIGQUIT, &act,NULL);
	//pthread_sigmask(SIG_BLOCK,&act.sa_mask,NULL);
	sleep(2);
}

int main()
{
	pthread_t tid1 ,tid2;
	int err;
	int s;
	err =pthread_create(&tid1,NULL,thread_fun1,NULL); 	
	if(err!=0) 
	{
       	printf("create tid1 failed\n") ;		
       	return -1; 	
  	  }
	
    	err =pthread_create(&tid2,NULL,thread_fun2,NULL); 	
	if(err!=0) 
	{
       	printf("create tid2 failed\n") ;		
       	return -2; 	
    }
    sleep(1);
    s =pthread_kill(tid1 ,SIGQUIT);
    if(s!=0)
    {
    	printf("send signal to thread1 failed\n");
    }
    s =pthread_kill(tid2 ,SIGQUIT);
    if(s!=0)
    {
    	printf("send signal to thread2 failed\n");
    }
	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	return 0;
}

结果:可能会出现thread2 get signal 或thread1 get signal
因为sigaction的作用是最后一次定义的,有可能是handler1或handler2,所以main中发送SIGQUIT信号时,有两种情况发生。

线程清理处理程序

  • pthread_cleanup_push(void(*rtn) (void), void *arg)   //注册处理程序
    -void(*rtn)(void *): 线程清理函数
  • pthread_cleanup_pop(int excute)    //清除处理程序

0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行(及当pthread_cleanup_pop()函数的参数为0时,仅仅在线程调用pthread_exit函数或者其它线程对本线程调用 pthread_cancel函数时,才在弹出“清理函数”的同时执行该“清理函数”)。

这两个函数要成对出现,否则编译无法通过。
当执行以下操作时调用清理函数,清理函数的参数由arg传入

  • 调用pthread_exit
  • 响应取消请求
  • 用非零参数调用pthread_cleanup_pop
#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "signal.h"
#include "string.h"
#include "unistd.h"

void *first_clean(void *arg) //处理函数1
{
	printf("%s first clean\n",arg);
	return(void *)0;
}
void *second_clean(void *arg)//处理函数2
{
	printf("%s second clean\n",arg);
	return(void *)0;
}
void * thread_fun1(void *arg)
{
	printf("new thread 1\n");
	pthread_cleanup_push(first_clean, "thread1");//注册处理函数1
	pthread_cleanup_push(second_clean,"thread1");//注册处理函数2
	pthread_cleanup_pop(1);   //调用执行second clean
	pthread_cleanup_pop(0);    //为0 不执行first clean
	return(void *)1;
}
void *thread_fun2(void *arg)
{
	printf("new thread 2\n");
	pthread_cleanup_push(first_clean, "thread2");
	pthread_cleanup_push(second_clean,"thread2");
	pthread_exit((void *)2);//会执行first clean 和second clea 虽然pop的参数是0
	pthread_cleanup_pop(0);
	pthread_cleanup_pop(0);
	
}
int main()
{
	pthread_t tid1,tid2;
	int err;
	err=pthread_create(&tid1,NULL,thread_fun1,NULL);
	if(err !=0)
	{
		printf("create nwe thread 1 failed\n");
		return -1;
	}

	err=pthread_create(&tid2,NULL,thread_fun2,NULL);
	if(err !=0)
	{
		printf("create nwe thread 2 failed\n");
		return -1;
	}
	sleep(2);
	return 0;
}

linux -多线程通信(二)信号的处理_第1张图片

你可能感兴趣的:(linux -多线程通信(二)信号的处理)