进程间通信---信号

信号

含义:
信号是给程序提供一种可以处理异步事件的方法.它利用软件中断来实现.不能自定义信号.所有信号都是系统预定义的.

信号如何产生:
1)由shell终端根据当前发生的错误(段错误.非法指令等)Ctrl+C而产生相应的信号.
比如:socket通信或者管道通信,如果读端都已经关闭.执行写操作(或者发送数据).将导致执行写操作的进程收到SIGPIPE信号(表示管道破裂)该信号的默认行为:终止该进程.
2) 在shell终端.使用kill或killall命令产生信号

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void myhandle(int sig) 
{
    
    
	printf("Catch a signal : %d\n", sig);
}
//该例子会导致按下Ctrl+C产生的信号被忽略.不会终止程序.需要用kill杀死程序
int main(void) 
{
    
    

	signal(SIGINT, myhandle);
	while (1) {
    
    
            sleep(1);
	}
	return 0;
}

有哪些信号:

SIGABORT     进程异常终止
SIGALRM 	 超时告警
SIGFPE 	     浮点运算异常
SIGHUP 	     连接挂断
SIGILL 		 非法指令
SIGINT 		 终端中断(Ctrl+C将产生该信号)
SIGKILL 	 终止进程                             
SIGPIPE 	 向没有读进程的管道写数据
SIGQUIT 	 终端退出(Ctrl+\将产生该信号)
SIGSEGV 	 无效内存段访问
SIGTERM 	 终止
SIGUSR1      用户自定义信号1
SIGUSR2 	 用户自定义信号2 
-------------------------------------->以上信号如果不被捕获.则进程接受到后都会终止.
SIGCHLD 	 子进程已停止或退出
SIGCONT 	 让暂停的进程继续执行
SIGSTOP 	 停止执行(即“暂停")
SIGTSTP 	 中断挂起
SIGTTIN 	 后台进程尝试读操作
SIGTTOU 	 后台进程尝试写
-------------------------------------------

信号的处理:

  1. 忽略此信号
  2. 捕捉信号.指定信号处理函数进行处理
  3. 执行系统默认动作.大多数都是终止进程

信号的捕获 :
信号的捕获.是指.指定接受到某种信号后.执行指定的函数.
SIGKILL和SIGSTOP不能被捕获.即.这两种信号的响应动作不能被改变.

信号集

信号集
1). 什么是信号集
信号集.用sigset_t类型表示.实质是一个无符号长整形.
用来表示包含多个信号的集合.
sigaction与signal的区别:sigaction比signal更“健壮”.建议使用sigaction.

 结构
   struct sigaction {
        void (*sa_handler)(int);   /* 信号的响应函数 */
        sigset_t  sa_mask;          /* 屏蔽信号集 */                         
        int sa_flags;               
  /* 当sa_flags中包含 SA_RESETHAND时.接受到该信号并调用指定的信号处理函数执行之后.把该信号的响应行为重置为默认行为SIG_DFL */
  }

2). 信号集的基本操作
sigemptyset 把信号集清空
sigfillset 把所有已定义的信号填充到指定信号集
sigdelset 从指定的信号集中删除指定的信号
sigaddset 从指定的信号集中添加指定的信号
sigismember 判断指定的信号是否在指定的信号集中
如果是.返回 1
如果不是.返回 0
信号无效.返回 -1
3) 进程的"信号屏蔽字"
进程的“信号屏蔽字”是一个信号集.想目标进程发送某信号时.如果这个信号在目标进程的信号屏蔽字中.则目标进程将不会捕获到该信号.即不会执行该信号的处理函数.当该进程的信号屏蔽字不再包含该信号时.则会捕获这个早已收到的信号(执行对应的函数)

    修改进程的"信号屏蔽字"
    使用sigprocmask
    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    参数:
    how:
    SIG_BLOCK    把参数set中的信号添加到信号屏蔽字中.原来的也有效 
    SIG_UNBLOCK  把参数set中的信号从信号屏蔽字中删除.删除原来存在的信号
    SIG_SETMASK  把参数set中的信号设置为信号屏蔽字.屏蔽原来存在的信号.新设置的有效
    oldset  返回原来的信号屏蔽字

4)获取未处理的信号
当进程的信号屏蔽字中信号发生时.这些信号不会被该进程响应.
可通过sigpending函数获取这些已经发生了但是没有被处理的信号

   用法:man sigpending
   返回值:成功则返回0.失败则返回-1

5)阻塞式等待信号
(1) pause
阻塞进程.直到发生任一信号后
(2) sigsuspend
用指定的参数设置信号屏蔽字.然后阻塞时等待信号的发生.即.只等待信号屏蔽字之外的信号.

demo.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void myhandle(int sig) 
{
    
    
	printf("Catch a signal : %d\n", sig);
	printf("Catch end.%d\n", sig);
}

int main(void) 
{
    
    
	struct sigaction act, act2;

	act.sa_handler = myhandle;//设置信号处理函数为myhandle
	sigemptyset(&act.sa_mask);//置空当前信号集
	act.sa_flags = 0;
	sigaction(SIGINT, &act, 0);//设置信号处理函数
	sigset_t proc_sig_msk, old_mask;//当前信号集与旧的信号集
	sigemptyset(&proc_sig_msk);//置空当前信号集
	sigaddset(&proc_sig_msk, SIGINT);//加入SIGINT信号
	sigprocmask(SIG_BLOCK, &proc_sig_msk, &old_mask);
	//将参数中的信号添加到信号屏蔽字中
	sleep(5);
	printf("had delete SIGINT from process sig mask\n");
	sigprocmask(SIG_UNBLOCK, &proc_sig_msk, &old_mask);//删除信号
		
	while (1) {
    
    
		
	}

	return 0;
}

在这里插入图片描述
当我们按下Ctrl+C的时候会发出SIGINT信号.但是由于我们一开始将SIGINT信号屏蔽了.所以并不会一开始就会生效.当过了5s后将屏蔽信号删除.系统接受到信号.调用信号处理函数.

补充:当sa_mask包含某个信号A时.则在信号处理函数执行期间.如果发生了该信号A.则阻塞该信号A(即暂时不响应该信号).直到信号处理函数执行结束.即.信号处理函数执行完之后.再响应该信号A.

猜你喜欢

转载自blog.csdn.net/qq_43507406/article/details/115421854