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;
}