信号(二)


1.向另一个进程发送信号

①kill函数

int kill(pid_t pid, int siq)
pid>0 将信号sig发给pid进程
pid=0 将信号sig发给同组进程
pid=-1 将信号sig发送给所有进程,调用者进程有权限发送的每一个进程(除了1号进程之外,还有它自身)
pid<-1 将信号sig发送给进程组是pid(绝对值)的每一个进程

例:子进程向父进程(同组进程)发送信号

void  myhandle(int num)
{
	if (num == SIGINT)
	{
		printf("recv signal SIGINT \n");
	}
	else if (num == SIGUSR1)
	{
		printf("recv signal SIGUSR1 \n");
	}
	else
	{
		printf("recv signal id num : %d \n", num);
	}
}


int main(void)
{

	pid_t 	pid;
	printf("main ....begin\n");
	
	if (signal(SIGINT, myhandle) == SIG_ERR)
	{
		perror("func signal err\n");
		return 0;
	} 
	if (signal(SIGUSR1, myhandle) == SIG_ERR)
	{
		perror("func signal err\n");
		return 0;
	} 
	
	pid = fork();
	if (pid == -1)
	{
		printf("fork err....\n");
		return 0;
	}
	
	//子进程向父进程发送信号
	//子进程向同组进程发送信号
	if (pid == 0)
	{
	    pid = getppid();
		kill(pid, SIGUSR1); //向父进程发信号
        //向进程组发信号
		kill(0, SIGUSR1);      //法一
        //pid = getpgrp();      //法二
		//killpg(pid, SIGUSR1);
		exit(0);
	}
	printf("sleep 函数执行完毕以后返回...\n");
	return 0;
}

②raise函数

给自己发送信号。raise(sig)等价于kill(getpid(), sig);

③sigqueue函数

int sigqueue(pid_t pid, int sig, const union sigval value) 价格
功能 针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。
返回值 成功:0,失败:-1
参数
pid 指定接收信号的进程id
sig 发送的信号
value 信号传递的参数
其中第三个参数为union sigval,下面是union sigval的内容:
typedef union sigval
{ 
    int sival_int; 
    void *sival_ptr; 
}sigval_t;      

注:在下面介绍的sigaction()函数的第二个参数结构体参数中,第二个处理器函数siginfo_t参数下有一个sigval_t值。。。

例:两个进程间通过 sigqueue 发送数据

void myHandle_forsigaction(int signum, siginfo_t *s_t, void *p)
{
	int myint = 0;
	printf("recv signum : %d \n", signum);
	myint = s_t->si_value.sival_int;
	printf("%d %d \n", myint, s_t->si_int );
}


int main(int argc, char *argv[])
{
	pid_t 	pid;
	int ret = 0;
	
	struct sigaction act;
	act.sa_sigaction = myHandle_forsigaction;
	sigemptyset(&act.sa_mask);
	
	//准备接受额外数据
	act.sa_flags = SA_SIGINFO;

	if (sigaction(SIGINT, &act, NULL) < 0)
		ERR_EXIT("sigaction error");
		
	pid = fork();
	
	if (pid == -1)
	{
		printf("fork err...\n");
		return 0;
	}
	
	if (pid == 0)
	{
		int i = 0;
		/*
		Teacher *t = (Teacher *)malloc(sizeof(Teacher));
		memset(t, 0, sizeof(Teacher));
		strcpy(t->name, "name");
		t->age = 33;
		*/
		
		
		/*
         union sigval {
             int   sival_int;
             void *sival_ptr;
         }; */
         
	   union sigval  mysigval;
	   //mysigval.sival_ptr = (void *)&t;
	   mysigval.sival_int = 222;	
	
		//kill(getppid(), SIGINT);
		//带额外数据
		for (i=0; i<10; i++)
		{
			ret  = sigqueue(getppid(), SIGINT, mysigval);
			if (ret != 0)
			{
				printf("sigqueue .....\n");
				exit(0);
			}
			else
			{
				printf("sigqueue...successs\n");
				sleep(2);
			}
		}

	}
	else if (pid > 0)
	{
		for (;;)
			pause();
	}

	return 0;
}

2.改变信号处置

从上一节可知,信号抵达后,有着不同的处理方式,如 `SIG_DFL` :执行默认的方式; `SIG_IGN` :忽略;或者执行信号处理器程序(即程序员自己编写的程序)。
首先介绍如何实现信号处理器程序。

①signal函数

__sighandler_t signal(int signum, __sighandler_t handler);
功能 忽略信号、设置信号默认处理或注册一个信号处理函数
返回值 返回修改前的handler函数指针
参数
signum 信号类型
handler 接收到指定信号时将要调用的函数

例1:信号的安装(注册SIGINT)

void handler(int num)
{
	printf("recv num:%d \n", num);	
}


void main()
{
	//注册一个信号
	//SIGINT  是ctrl+c 会产生2号信号。。。 中断应用程序
	signal(SIGINT, handler);
	
	while(1)
	{
		pause();
	}
	
	printf("main...Begin\n");
		
}

例2:信号的恢复

int main(void)
{
	__sighandler_t oldHandle;       //保留原处理信号行为
	printf("main ....begin\n");
	oldHandle = signal(SIGINT, myhandle); 
	if (oldHandle == SIG_ERR)
	{
		perror("func signal err\n");
		return 0;
	} 
	
	printf("if u enter a, reset signal \n");
	while(getchar() != 'a')
	{
		;
	}

    //键入a以后,信号的恢复 
	//法一:恢复默认函数
	/*
	if (signal(SIGINT, oldHandle) == SIG_ERR)
	{
		perror("func signal err\n");
		return 0;
	}
	*/
	//法二:
	if (signal(SIGINT, SIG_DFL) == SIG_ERR)
	{
		perror("func signal err\n");
		return 0;
	}
		
	while(1) ;
	return 0;

}

②sigaction函数

int sigaction(int signum,const struct sigaction *act,const struct sigaction *old)
功能 注册一个信号处理函数
返回值 成功:0,失败:-1
参数
signum 信号类型
act 指向结构sigaction的一个实例的指针
old 保存原来对相应信号的处理
第二个参数act包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些信号等等。下面是struct sigaction的内容:
struct sigaction {
	void (*sa_handler)(int);   //信号处理程序一: 不接受额外数据,同signal()的第二个参数
	void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序二:能接受额外数据,和sigqueue配合使用 
	sigset_t sa_mask; //定义一组信号,不允许中断此处处理程序的执行
	int sa_flags; //影响信号的行为   SA_SIGINFO表示能接受数据
	void (*sa_restorer)(void); //废弃
};

由于struct sigaction结构中信号处理程序一与之前在signal中介绍的处理函数相似,所以接下来介绍信号处理程序二的使用。
第二个参数siginfo_t内容如下:
 siginfo_t {
              int      si_signo;  /* Signal number */
              int      si_errno;  /* An errno value */
              int      si_code;   /* Signal code */
              pid_t    si_pid;    /* Sending process ID */
              uid_t    si_uid;    /* Real user ID of sending process */
              int      si_status; /* Exit value or signal */
              clock_t  si_utime;  /* User time consumed */
              clock_t  si_stime;  /* System time consumed */
              sigval_t si_value;  /* Signal value */  
              int      si_int;    /* POSIX.1b signal */
              void *   si_ptr;    /* POSIX.1b signal */
              void *   si_addr;   /* Memory location which caused fault */
              int      si_band;   /* Band event */
              int      si_fd;     /* File descriptor */
            }

注:
①si_code:表示信号来源,对于通过sigqueue()发送的实时信号来说,该字段为SI_QUEUE
②si_value:由进程使用sigqueue()发送信号时在value参数中指定

③signal()与sigaction()

sigaction()是建立信号处理器的首选API,较之signal()可移植性更佳。而往往使用signal()将信号处置设置为SIG_IGN或SIG_DFL。

例:用sigaction模拟signal函数

void handler(int sig)
{
	printf("recv a sig=%d\n", sig);	
}

__sighandler_t my_signal(int sig, __sighandler_t handler)
{
	struct sigaction act;
	struct sigaction oldact;
	act.sa_handler = handler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;

	if (sigaction(sig, &act, &oldact) < 0)
		return SIG_ERR;

	return oldact.sa_handler;
}

int main(int argc, char *argv[])
{         
	struct sigaction act;
	sigset_t sa_mask;
	
	act.sa_handler = handler;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);

	//测试信号安装函数
	//sigaction(SIGINT, &act, NULL);
	
	//模拟signal函数
	my_signal(SIGINT, handler);

	for (;;)
	{
		pause();
	}
	return 0;
}

posted @ 2018-07-15 15:32  神秘的火柴人  阅读(157)  评论(0编辑  收藏  举报