linux系统中的信号处理

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值