Linux进程信号

每一个信号都有一个编号和一个宏定义的名称,这些宏定义可以再signal.h中找到。编号34以上的为实时信号。

关于每个信号的作用是什么我们可以通过man指令去查看,例如:man 9 signal。其中数字对应第几号信号。

信号产生的方式:

  • 用户在终端的某些按键会发送信号给前台进程。例如ctrl+c产生SIGINT信号。
  • 硬件异常产生信号。例如如果访问了非法地址,内核将发送一个SIGSEGV发送给进程。
  • 一个进程可以调用kill(2)函数给另外一个进程发送信号。
  • 软件条件产生。

通过终端按键产生信号

  1. SIGINT的默认处理动作是终止进程。
  2. SIGQUIT的默认处理动作是终止进程并且Core Dump(当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上)。

使用系统函数向进程发送信号

      在这里我们用到的函数为:int kill(pid_t pid,int signo);pid为需要发送信号的进程,signo则为索要发送的信号

      kill指令的实现就是调用kill函数,调用指令方式为kill -11 1234;这里11为信号编号,也可以不写编号直接写信号名,1234为进程id。

#include<stdio.h>
int main()
{
	printf("get pid = %d\n",getpid());	
	while(1);
	return 0;
}
我们在这里写一个死循环,然后启用另一个终端利用kill函数将它关闭。

  


在这里我们也可以了解一下另外两个函数

int raise(int signo);这个函数与kill函数唯一的区别是只能给自己发信号,且返回值成功为0,失败为1。

void abort(void);这个函数可以使当前进程接收到信号而终止异常。

由软件条件产生信号

这里我们先了解一个函数

unsigned int alarm(unsigned int seconds);

调用这个函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发送一个SIGALRM信号,该信号会终止当前进程。这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。

#include<stdio.h>
#include<unistd.h>
int main()
{
	int i = 1;
	alarm(1);
	for(;1;i++)
		printf("i = %d ",i);
	return 0;
}

我们来用这个程序了解一下alarm函数的作用。


由结果可以看出,在闹钟提醒前代码正常运行,但当alarm函数运行后进程立即被打断了。

阻塞信号

要了解阻塞信号我们要先了解一下信号和其他的一些常见的概念

  1. 实际执行信号的处理动作成为信号递达。
  2. 信号从产生到递达之间的状态,成为信号未决。
  3. 进程可以阻塞某个信号。
  4. 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞。
  5. 阻塞和忽略是不同的,信号被阻塞不会被递达,而忽略是收到信号后的一种动作。

      每个信号都有两个标志位分别表示阻塞(block)和未决,还有一个函数指针表示接收到该信号后的动作。

      对于图中SIGHUP信号,因为未产生也不阻塞,所以若该信号产生则进行默认操作。

      对于图中SIGINT信号,虽然产生过但被阻塞了,所以并不会被递达。

      对于图中SIGQUIT信号,一旦产生就会被阻塞,不能递达。

因为每个信号只有一个bit的未决标志,非0即1,阻塞标志也是这样的,因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储。

* 信号集操作函数

sigprocmask

     调用此函数可以读取或更改进程的信号屏蔽字。

int sigprocmask(int how,const sigset_t *set,sigset_t *oset)返回值成功为0,失败为-1。

sigpending

     调用此函数可以读取当前进程的未决信号集,通过set参数传出,调用成功返回0,失败返回-1。

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void printsigset(sigset_t* p)
{
	int i = 0;
	for(;i<32;i++)
	{
		if(sigismember(p,i))
			putchar('1');
		else
			putchar('0');
	}
	puts("");
}
int main()
{
	sigset_t p,s;
	sigemptyset(&s);
	sigaddset(&s,SIGINT);
	sigprocmask(SIG_BLOCK,&s,NULL);
	while(1)
	{
		sigpending(&p);
		printsigset(&p);
		sleep(1);
	}
	return 0;
}

在这段代码中我们将SIGINT信号屏蔽掉,运行后看一下结果。


由运行结果可以看出,crtl+c已经不能结束进程了,因为这个信号已经被屏蔽掉了。

信号捕捉

      当前正在执行函数时,这时发生异常或者中断进入到了内核态,中断处理完后,这时如果检测到有信号递达,内核就会在返回到用户态后优先去执行该信号对应的函数,在执行完成后会继续进入到内核态,这时如果没有新的信号递达,内核才会恢复main函数的上下文继续执行。

可重入函数

     只访问自己局部变量或者参数的函数称为可重入函数,可能因为重入导致错误的函数称为不可重入函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值