【Linux】进程间通信----信号

1.信号

1)信号是进程之间事件异步通知的一种方式,属于软中断。

2)信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。

3)如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

信号的种类
1~31:非可靠信号
34~64:可靠信号

 

2.常见的信号

硬件产生

  • SIGINT (2):ctrl+c 终止信号
  • SIGQUIT (3):ctrl+\ 终止信号
  • SIGTSTP (20):ctrl+z 暂停信号
  • SIGALRM:闹钟信号 收到此信号后定时结束,结束进程
  • SIGCHLD:子进程状态改变,父进程收到信号
  • SIGKILL:杀死信号

 
软件产生

  • kill函数 kill(pid_t pid, int signo)
  • kill -[信号][pid] :kill -9 12121
  • abort(pid_t pid):6号信号(SIGABORT) // double free
  • 解引用空指针+内存访问越界---->进程收到 SIGSEGV(11)

 

3.信号的注册

在这里插入图片描述

  • 在使用sig数组的时候不是按照数组的方式去使用的,而是按照比特位的方式去使用的
  • 对于sig位图当中的bit位,每一个比特位有与之对应的信号,直到将我们当前操作系统的信号表示完毕

 

  • 当进程收到一个非可靠信号
  • 第一件事情:将非可靠信号对应的比特位更改为1
  • 第二件事情:添加sigqueue节点到sigqueue队列当中
  • 注意:队列当中已经有了该信号的sigqueue节点,则不添加
     
  • 如果进程收到一个可靠信号
  • 第一件事情:在sig位图当中更改该信号对应的比特位为1
  • 第二件事情:不论之前sigqueue队列当中是否存在该信号的sigqueue节点,都再次添加sigqueue节点到sigqueue队列当中;

 

4.信号的注销

  • 非可靠信号的注销
  • 该信号的sigqueue节点从sigqueue队列当中的出队操作
  • 信号在sig位图当中对应的比特位从1置为0
     
  • 可靠信号的注销
  • 将该信号的sigqueue节点从sigqueue队列当中进行出队操作
  • 需要判断sigqueue队列当中是否还有相同的sigqueue节点
    没有:信号在sig位图当中对应的比特位从1置为0
    有:不会更改sig位图当中对应的比特位
     

5.信号的处理方式

1)默认处理(SIG_DFL):执行该信号的默认处理动作。注意,对大多数信号的系统默认动作是终止该进程。

2)忽略处理(SIG_IGN):对信号不做任何处理,但是有两个信号不能忽略:即SIGKILL及SIGSTOP。

3)捕捉信号(自定义信号处理方式):定义信号处理函数,当信号发生时,执行相应的处理函数。

sighanler_t signal(int signum, sighhandler_t handler); // 将signum的处理方式修改为handler
typedef void (*sighandler_t )(int); // 上行函数的自定义处理方式

在这里插入图片描述

// 自定义处理应用
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void sigback(int signo)
{
  printf("signo :%d\n", signo);
}

int main()
{
  signal(2, sigback);
  while(1)
  {
    printf("linux so easy!\n");
    sleep(1);
  }
  return 0;
}

 

6.sigaction函数

sigaction

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)

参数

  • signum:待更改的信号的值
  • act:将信号处理函数改变act
  • oldact:信号之前的处理方式
struct sigaction {
	void (*sa_handler)(); /* 保存内核对信号的处理方式 */
	sigset_t sa_mask; /* 保存的是当前进程在处理信号的时候,收到的信号 */
	int sa_flags; /* SA_SIGINFO:对信号处理程序提供了附加信息*/
}

 
sigempty

int sigempty(sigset_t *set); // 将位图的所有比特位设置为0
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void sigback(int signo)
{
  printf("signo: %d\n", signo);
}

int main()
{
  // act--->入参
  struct sigaction act;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
  act.sa_handler = sigback;

  // old--->出参
  struct sigaction oldact;
  sigaction(2, &act, &oldact);

  getchar();

  sigaction(2, &oldact, NULL);

  while(1)
  {
    printf("linux so easy!\n");
    sleep(1);
  }
  return 0;
}

 

7.信号的捕捉流程

在这里插入图片描述

  • 用户空间到内核空间:中断、异常、系统调用函数、库函数时(库函数底层大多数都是封装系统调用函数的)

捕捉信号
在这里插入图片描述

从用户态到内核态的过程是权限升级的过程,而从内核态到用户态的过程是要从安全方面考虑的,因为操作系统不相信任何人,只相信它自己,所以要想要访问操作系统内部进行访问时必须通过系统调用接口。

操作系统的代码只能由操作系统执行,用户的代码就只能由用户执行,因此就会有内核态和用户态两种状态之间的相互转变。
 

8.信号在内核的三种状态

1)信号递达(Delivery):实际执行信号的处理动作称为信号递达;

2)信号未决(Pending):信号从产生到递达之间的状态;

3)信号阻塞(Block):被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作;

信号屏蔽字

// 读取或更改进程的信号屏蔽字
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

参数

  • how:告诉sigprocmask函数,应该进行什么操作
    SIG_BLOCK:设置每个信号为阻塞
    SIG_UNBLOCK:解除对某个信号的阻塞
    SIG_SETMASK:替换阻塞位图

  • set:用来设置阻塞位图
    SIG_BLOCK:设置某个信号为阻塞 block(new) = block(old) | set
    SIG_UNBLOCK:解除对某个信号的阻塞 block(new) = block(old) & (~set)
    SIG_SETMASK:替换阻塞位图 block(new) = set

  • oldset:原来的阻塞位图

#include <signal.h>
#include <iostream>
using namespace std;

int main()
{
	sigset_t sigset;
	if(sigprocmask(0, NULL, &sigset) < 0){
		cout << "sigprocmask error"<< endl;
	}
	if(sigismember(&sigset, SIGINT)) printf("SIGINT");
	if(sigismember(&sigset, SIGQUIT)) printf("SIGQUIT");
	if(sigismember(&sigset, SIGSR1)) printf("SIGSR1");
	if(sigismember(&sigset, SIGALRM)) printf("SIGALRM");
	printf("\n");
	return 0;
}

未决信号集

// 读取当前进程的信号未决集,通过set参数传出
int sigpending(sigset_t *set);

返回值

  • 成功返回0,出错返回-1。

 

8.信号的阻塞

在这里插入图片描述

  • 信号的阻塞并不会干扰信号的注册,只不过当前的进程不能立即处理
     
  • 当我们将block位图当中对应信号的比特位置为1,表示当前进程阻塞该信号
  • 当进程收到一个信号的时候,进程还是一如既往的对该信号进行注册
  • 当进程进入到内核空间,准备返回用户空间的时候,调用do_signal函数,这会儿不会立即去处理该信号了
  • 不会立即处理:延迟处理
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值