linux系统中的信号处理

来源:互联网 发布:mac怎么文件夹压缩 编辑:程序博客网 时间:2024/05/01 06:07

1.1信号的概念

信号:信号是异步传送给进程的时间通知,进程无法准确地预测合适会出现信号。

同步信号:程序中的某个具体的操作相关并且在那个操作进行的同时产生。

异步信号:进程之外的事件产生的信号。

当信号发生时进程采取的动作:

1)忽略信号。

2)捕获信号。

3)执行系统默认动作。

1.2 kill( )函数

#include <signal.h>int kill(pid_t pid, int sig);
pid > 0:把信号发送给ID为pid的进程。

pid == 0:把信号发送给进程所在进程组的所有进程。

pid < -1:把发送给ID为pid的绝对值的进程组(发送者有权发送)。

pid == -1:广播信号,发送给发送者有权发送的所有进程。

sig:信号。

执行成功返回0,失败返回-1并且置error指出错误原因。

为了防止随意的杀死属于其他用户的进程,一般发送信号的实际用户ID或有效ID必须与接受信号的实际用户ID或有效ID相同。root用户有权向任意用户发送信号。

使用kill( )函数发送信号的例子:

#include <signal.h>#include <stdio.h>#include <stdlib.h>int flag = 0; /*标志变量*/void sig_usr(int sig) /*信号句柄*/{flag = 1;}void child()   /*子进程调用,发送给父进程SIGUSR1信号*/{printf("My Pid is %d \n",(int)getpid());kill(getppid(),SIGUSR1);printf("life over!\n");exit(0);}int main(){pid_t ch;signal(SIGUSR1,sig_usr);  /*设置信号动作*/if((ch = fork()) ==  -1)  /*如果创建子进程失败,退出*/{fprintf(stderr,"faild!\n");exit(-1);}if(ch == 0)  /*如果是子进程*/child();while(!flag); /*循环等待SIGUSR1信号的出现*/fprintf(stdout,"voer!\n");return 0;}
1.3设置信号动作

#include <signal.h>typedef void (*sighandler_t) (int);sighandler_t signal(int signum,sighandler_t handler);
signum:指明是那种信号。

handler:信号发生时应该采取的动作。

返回值:前一次有效动作的指针。

signal的缺陷:

void sig_usr(int sig){   .......   signal(SIGUSR1 sig_usr); /*设置SIGUSR1信号句柄*/}int main(){   signanl(SIGUSR1,sig_usr);   ...}
当在执行SIGUSR1信号句柄时,SIGUSR1信号在执行设置SIGUSR1信号句柄前出现,将导致进程的终止。因为在执行信号句柄时系统将重置该信号的动作为默认动作。signal是不可靠的,应该使用可靠的sigaction设置信号的动作。


使用signal( )设置信号的动作:

#include <signal.h>#include <stdlib.h>#include <stdio.h>#include <unistd.h>static void sig_usr(int sig) /*信号句柄*/{fprintf(stdout,"voer!\n");return;}int main(){if(signal(SIGUSR1,sig_usr) == SIG_ERR) /*设置信号动作*/{fprintf(stderr,"failg!\n");exit(1);}while(1) /*挂起直到有SIGUSR1信号出现*/{        pause();}        return 0;}

sigaction( )函数

#include <signal.h>int sigaction(int signum,const strcut sigaction *act,strcut sigaction *oact);
signum:制定的信号。

act:设置信号的动作。

oact:保存前一信号的动作。

act为NULL,oact不为NULL查询当前的信号动作。

act不为NULL,oact为NULL设置信号动作。

act,oact不为NULL,设置信号动作,并保存前一信号动作。

调用成功返回0,不成功返回-1,且不安装新动作;

结构体sigaction定义:

struct sigaction{   void (*sa_handler) ( );   void (*sa_sigaction) (int,siginfo_t*,siginfo*);   sigset_t  sa_mask;   int  sa_flags;};

第一个成员变量:指定与信号相连的动作,指定一个信号句柄。

第二个成员变量:指定与信号相连的动作,指定一个信号句柄。

第三个成员变量:sa_mask要屏蔽的信号集合。

第四个成员变量:sa_flags 标志变量。

当设置sa_flags为SA_SIGINFO则sa_hanler的函数原型为void func(int signo,siginfo *info,void *context)【实时句柄】;
否则为void func (int signo);

1.4 阻塞信号
阻塞信号:告诉操作系统保持该信号并推迟它的发送,它们只是暂时的挂起,知道阻塞解除。
sigset_t类型和集合集的操作:

#include <signal.h>int sigempty(sigset_t *set); /*清空信号集合*/int sigfillset(sigset_t *set); /*填满信号集合*/int sigaddset(sigset_t *set,int signo); /*向信号集合中添加信号*/int sigdelset(sigset_t *set,int signo); /*删除集合中的指定信号*/int sigismember (const sigset_t *set,int signo); /*查看信号机中的成员*/
调用失败返回-1,成功返回0;

设置屏蔽信号:

#include <signal.h>int sigprocmask (int how,const sigset_t *set,sigset_t *oset); /*改变调用进程的状态*/

how:如何改变信号的屏蔽。

SIG_BLOCK:阻塞set所指信号集的信号集,即将它们加入到当前的信号屏蔽中。

SIG_UNBLOCK:放开set所指的信号集,即将它们从当前的信号屏蔽中删除。

SIG_SETMASK:用set所指的信号集作为进程新的信号集,抛弃原先的信号屏蔽值。

set为NULL,oset不为NULL只查看,不改变。

set不为NULL,oset为NULL只改变。

set和oset都部位NULL,改变屏蔽信号,保存前一信号到oset。

sigpromask( ) 不能阻塞SIGKILL和SIGSTOP信号。

检查挂起信号:

#include <signal.h>int sigpending (sigset_t *set); /*检查挂起信号*/

检查挂起信号:

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>int main(){sigset_t base,old,work; /*定义信号集*/int sig;sigemptyset(&base);    /*清空将要设置的信号集*/sigaddset(&base,SIGQUIT); /*添加SIGQUIT信号*/sigaddset(&base,SIGSTOP); /*添加SIGSTOP信号*/if(sigprocmask(SIG_BLOCK,&base,&old) < 0)  /*屏蔽base信号集的信号*/fprintf(stderr,"mask faile!\n");fprintf(stdout,"Plase weite!\n");sleep(10);   /*睡眠10秒*/sigpending(&work); /*查看挂起的信号集*/for(sig = 1; sig < NSIG; sig++)    /*遍历挂起的信号集*/if(sigismember(&work,sig))psignal(sig,"there is a pending signel!\n");if(sigprocmask(SIG_BLOCK,&old,NULL) < 0)  /*恢复旧的屏蔽信号*/exit(1);printf("over!\n");exit(0);   /*退出*/}

1.5 等待信号

include <unistd.h>voud pause(void) /*挂起调用进程直到有信号到达*/
只有这个信号执行句柄函数并且句柄函数返回时,pause()系统调用才会返回。

paus()隐藏这严重的时间窗口错误,导致程序的神秘挂起。

<span style="font-size:14px;">#include <signal.h>int sigsuspend(cost sigset_t *sigmask); /*挂起sigmask信号集,知道有不属于sigmask信号集的信号到来*/</span>
使用sigmask的信号集暂时代替进程的信号屏蔽,挂起调用进程直到有不属于sigmask的信号到来。

#include <signal.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>volatile int falg = 0;static void sig_usr(int signo)   /*信号SIGUSR1和信号SIGUSR2的语句柄*/{psignal(signo,"received!\n");}static void sig_intr(int signo)  /*信号SIGINT的语句柄,置位标识变量*/{psignal(signo,"received!\n");        falg = 1;}void wait_for_signal(int sig,volatile int *f) /**/{static sigset_t mask,oldMask;sigemptyset(&mask);           /*清空信号集*/sigaddset(&mask,sig);         /*添加信号集*/if(sigprocmask(SIG_BLOCK,&mask,&oldMask) < 0) /*暂时屏蔽mask信号的集合*/{fprintf(stderr,"SIG_BOLK error!\n");exit(1);}        sigdelset(&oldMask,SIGUSR1);     /*从前一信号集合中删除SIGUSR1*/        sigdelset(&oldMask,SIGUSR2);     /*从前一信号集合中删除SIGUSR2*/while(!*f)                       /*循环等待SIGINT信号的到来*/{printf("Open!\n");sigsuspend(&oldMask);printf("Close\n");}*f = 0;if(sigprocmask(sig,&oldMask,NULL) < 0)  /*恢复前一屏蔽信号集*/fprintf(stderr,"fail\n");}int main(){pid_t pid;static sigset_t mask,oldmask;signal(SIGUSR1,sig_usr);      /*为SIGUSR1信号添加语句柄*/signal(SIGUSR2,sig_usr);      /*为SIGUSR2信号添加语句柄*/signal(SIGINT,sig_intr);      /*为SIGINT信号添加语句柄*/sigemptyset(&mask);           /*清空mask信号集*/sigaddset(&mask,SIGUSR1);     /*添加SIGUSR1信号集合*/sigaddset(&mask,SIGUSR2);     /*添加SIGUSR2信号集合*/if(sigprocmask(SIG_BLOCK,&mask,&oldmask) < 0) /*暂时屏蔽mask信号集合*/{fprintf(stderr,"SIG_BLOCK\n");exit(1);}if((pid = fork()) == 0)    /*创造子进程*/{kill(getppid(),SIGUSR1); /*给父进程发送SIGUSR1信号*/kill(getppid(),SIGUSR2); /*给父进程发送SIGUSR2信号*/printf("child OK\n");    while(1);  /*循环等待*/}else{wait_for_signal(SIGINT,&falg);printf("Now,I can do my work!\n"); kill(pid,SIGTERM); /*杀死子进程*/}exit(0);}

1.6 原子数据

对它的访问操作不会在半途中断的数据,任何访问它的操作要么没有完成,要么已经完成,不存在中间状态。






0 0
原创粉丝点击