进程间通信(二)——信号

系列文章目录

进程间通信(零)——说明
进程间通信(一)——管道
进程间通信(二)——信号
进程间通信(三)——共享内存
进程间通信(四)——信号量



一、信号的概念

Linux中响应各类事件的机制

常用的信号有:
SIGINT 程序终止信号。按下Ctrl+C时通知前台进程组终止进程
SIGQUIT 类似程序错误信号,Ctrl+\控制,进程退出时会产生core文件
SIGILL 表示执行了非法指令。通常是 可执行文件 出现错误,或数据段、堆栈溢出可能产生
SIGBUS 非法地址。包括内存地址对齐出错。

二、信号调用

1.所有的信号

在ubuntu系统输入 “kill -l”来查看。

 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

2.发送信号

#include<signal.h>
int kil(pid_t pid,int sig);		// 发送信号
参数
	pid		给谁发送信号
				pid > 0		给特定的某个进程发送信号
				pid = 0		给在同一进程组下的进程发送信号
				pid = -1		给任意有权限的进程发送信号
				pid < -1		给进程组id号为  |pid|的进程法信号

	sig		发送什么信号
返回值		成功 —— 0	 失败 —— -1

比如,kill(2230, 2); // 表示给pid为2230的进程发送信号2
示例,我们创建一个kill1.c的应用,实现根据输入的信号和pid号进行发送。

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#define N 3
int main(int argc,char *argv[])
{
	if(argc<N)
	{
		printf("Please use:%s <pid> <sig>\n",argv[0]);
		exit(-1);
	}

	kill(atoi(argv[1]),atoi(argv[2]));
    return 0;
}

3.注册自定义信号

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);		// 信号注册
参数:
	signum		注册信号的编号		signal(2,)	给信号2注册
	handler
		SIG_IGN		忽略
		SIG_DFL		默认(缺省)
				捕捉	-> 调用 		执行相对于的自定义操作
		919 不能被捕捉,不能被忽略,不能被注册

示例:当函数接受到信号2后执行hello函数

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>

void hello(int sig)
{
	printf("hello\n");
}
int main(int argc,char *argv[])
{

    signal(2, hello);

	while(1)
	{
		sleep(1);
		printf("mypid:%d\n",getpid());
	}
    return 0;
}

测试:

  • 运行应用
    在这里插入图片描述

  • 运行前面发送信号的app
    在这里插入图片描述

  • 收到信号2后,进程会打印hello
    在这里插入图片描述

4.挂起信号

#include <unistd.h>
int pause(void);		// 挂起
	阻塞,直到收到信号,信号被捕捉,执行完捕捉函数后,解除阻塞,继续往下
返回值:	-1

5.消息队列

三、信号——经典案例

模拟司机售票员:子进程表示售票员,父进程表示司机

(1)售票员捕捉SIGINT(2)信号(代表开车),发送SIGUSR1(10)给司机,司机捕捉到该信号后打印“move to next station”
(2)售票员捕捉SIGQUIT(3)信号(代表靠站),发送SIGUSR2(12)给司机,司机捕捉到该信号后打印“stop to bus”
(3)司机捕捉到SIGTSTP(20)信号(代表车到总站),发送SIGUSR1(10)给售票员,售票员捕捉到给信号后打印“all get off the bus”

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
static pid_t pid = -1;

void cond(int sig)
{
	switch(sig)
	{
		case SIGINT:
			printf("Cond sig:%d\n",sig);
			kill(getppid(), SIGUSR1);
			break;
		case SIGQUIT:
			printf("Cond sig:%d\n",sig);
			kill(getppid(), SIGUSR2);
			break;
		case SIGUSR1:
			printf("all get off the bus\n");
		default:
			break;
				
	}
}

void driver(int sig)
{
	switch(sig)
	{
		case SIGUSR1:		// 10
			printf("move to next station\n");
			break;
		case SIGUSR2:		// 12
			printf("stop to bus\n");
			break;
		case SIGTSTP:		// 20
			kill(pid, SIGUSR1);
		default:
			break;
		
	}
}

int main(int argc,char *argv[])
{

	pid = fork();
	if(pid < -1){
		perror("fork fail");
		exit(1);
	}else if(pid == 0){		// 子进程
		signal(SIGTSTP, SIG_IGN);	// 忽略
	
		signal(SIGINT, cond);	// 信号2
		signal(SIGQUIT, cond);	// 信号3
		signal(SIGUSR1, cond);	// 信号10
		printf("Son %d,father %d\n",getpid(),getppid());
		while(1){
			pause();
		}
	}else {		// 父进程
		signal(SIGINT, SIG_IGN);	// 忽略
		signal(SIGQUIT, SIG_IGN);
		
		signal(SIGUSR1, driver);	// 信号10
		signal(SIGUSR2, driver);	// 信号12
		signal(SIGTSTP, driver);	// 信号20
		//printf("Now %d,grand father %d\n",getpid(),getppid());
		sleep(1);
		while(1){
			pause();
		}
	}
    return 0;
}

测试:
在这里插入图片描述
可以看到子进程pid是 28874,父进程pid是28873
1、向子进程发送信号
(1)收到SIGINT
在这里插入图片描述

(2)收到SIGQUIT
在这里插入图片描述

(3)收到SIGUSR1
在这里插入图片描述

2、向父进程发送信号
(1)收到SIGTSTP
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值