02进程间通信——信号

1. 信号(signal)

信号是进程间通信的一种方式,这种方式没有传输用户数据。只是在内核中传一个信号(整数),信号的本质是一个整数值


不同的信号值(整数),代表不同的含义(OS设定好的),当然用户可以自定义信号,自定义信号的含义和值由程序员来决定和解释

Signal(名称)  Value(整数值)  Action(动作)   Comment(注释) 
──────────────────────────────────────────────────────────────────────
SIGHUP        1       Term    Hangup detected on controlling terminal
                                     or death of controlling process
// Term:Termination  终止 
/* 注释:控制终端的挂起操作(???),或是控制终端进程死亡时,依附于控制终端的所有进程
         都会收到SIGHUP信号 */

SIGINT        2       Term    Interrupt from keyboard
/* 注释:从键盘上收到的中断信号,CTRL + C
        CTRL + C,发一个SIGINT的信号给占用控制台的进程 */

SIGQUIT       3       Core    Quit from keyboard
// Core:保存当时进程的上下文信息(产生core文件),然后终止
/* 注释:从键盘上收到的退出信号 */

SIGILL        4       Core    Illegal Instruction
/* 注释:非法指令 */

SIGABRT       6       Core    Abort signal from abort(3)
/* 注释:调用abort这个函数的时候,进程会收到SIGABRT这个信号 */

SIGFPE        8       Core    Floating-point exception
/* 注释:浮点数例外(除0,取余0)
         浮点数运算异常的时候,进程会收到SIGAFPE这个信号 */

SIGKILL       9       Term    Kill signal
SIGSTOP   17,19,23    Stop    Stop process
/* 注释:无条件终止进程,不可修改默认操作(不可以被捕捉) */

SIGSEGV      11       Core    Invalid memory reference
/* 注释:非法内存访问时,会收到SIGSEGV这个信号
        ========> Segamation fault */
        
SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                     readers; see pipe(7)
/* 注释:当你往一个管道写数据的时候,没有读端进程,就会产生这个SIGPIPE信号 */

SIGALRM      14       Term    Timer signal from alarm(2)
/* 注释:定时信号,在进程调用alarm时,就会在"闹钟"超时的时候,产生SIGALRM信号 */

SIGTERM      15       Term    Termination signal
/* 注释:终止信号 */

SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
/* 注释:用户自定义信号,由程序员自己设定 */

SIGCHLD   20,17,18    Ign     Child stopped or terminated
// Ign:默认行为是忽略这个信号
/* 注释:当子进程停止或者终止时,父进程会收到这个信号 */

SIGCONT   19,18,25    Cont    Continue if stopped

SIGTSTP   18,20,24    Stop    Stop typed at terminal
SIGTTIN   21,21,26    Stop    Terminal input for background process
SIGTTOU   22,22,27    Stop    Terminal output for background process
......

进程在收到一个信号的时候,通常会有三种处理方式:

(1) 捕捉信号

        把一个信号和用户自定义的信号处理函数关联起来,那么进程在收到该信号的时候,就会自行调用该处理函数

(2) 默认行为

        进程收到一个信号时,默认采用操作系统默认的行为,大部分信号的默认行为,会把进程给终止

(3) 忽略该信号

2. 信号的处理过程

通过"软中断"来实现的

用户态:程序在执行用户自己的代码

内核态:执行OS的代码

3. linux下信号相关的 API 函数

(1) 发送信号   kill
NAME
    kill - send signal to a process
SYNOPSIS
    #include <sys/types.h>
    #include <signal.h>

// kill是用来把一个信号发送到一个指定的进程或者多个进程
int kill(pid_t pid, int sig);

    pid:指定信号的接收者进程(可能是多个进程)
         pid > 0:pid就表示接收者的进程号
         pid == 0:发送信号给调用者进程同组的所有进程
         pid == -1:发送给所有进程(有权限发送的所有进程)
         pid < -1:发送信号给组id等于pid绝对值的所有进程
    sig:你要发送的信号的值

    返回值:
        成功(至少有一个进程成功的收到信号)返回0
        失败返回-1,同时errno被设置
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>

int main() {
	sleep(5); // 5秒后杀死自己
	int r = kill(0, SIGKILL);
	while (1);
	return 0;
}
(2) 发送信号给自己   raise
NAME
    raise - send a signal to the caller
SYNOPSIS
    #include <signal.h>

// raise用来发送信号给调用者本身
int raise(int sig);
    
    sig:你要发送的信号的值
        raise(sig); <=====> kill(getpid(), sig);

    信号处理完后(自己设置信号处理函数),raise才会返回
    
    返回值:
        成功返回0
        失败返回一个非0的数
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>

int main() {
	sleep(5); // 5秒后杀死自己
	raise(SIGKILL);
	while (1);
	return 0;
}
alarm :定时发送一个闹钟信号(SIGALRM)给调用者进程

        "闹钟":每一个进程都有一个属于自己的“闹钟”,设定的时间到了,进程会收到SIGALRM这个信号,但是一个进程永远只有一个闹钟生效

NAME
    alarm - set an alarm clock for delivery of a signal
SYNOPSIS
    #include <unistd.h>
		
// alarm用来给调用者进程的“闹钟”定时
unsigned int alarm(unsigned int seconds);
		
seconds:设置“闹钟”的超时时间,单位为秒
    如:alarm(10); // 10秒后,进程就会收到“闹钟”信号
	设置一个“闹钟”的超时时间,会自动的把上一次设置的“闹钟”取消
	seconds == 0 取消闹钟
		
返回值:
	返回上一个闹钟的剩余秒数
	一个进程同一时刻只有一个闹钟
#include <stdio.h>
#include <unistd.h>

int main() {
	alarm(10); // 10秒后给调用者进程一个闹钟信号
	sleep(3);
	int r = alarm(3); // 重新设定超时时间
	printf("r = %d\n", r);
	while (1);
	return 0;
}

r = 7
闹钟

大部分信号的默认行为,就是把收到信号的进程给干掉,在实际应用的时候,我们一般会修改默认行为(当条件发送的时候,做指定的任务)
        改变信号的处理方式 -----> 捕捉信号

(3) 捕捉信号:改变信号的处理方式

把具体的信号与具体的处理方式相关联

NAME
    signal - ANSI C signal handling
SYNOPSIS
    #include <signal.h>

typedef void (*sighandler_t)(int);

    定义了一个类型,类型名字是sighandler_t
    typedef:定义一个已有类型的别名
	sighandler_t是一个函数指针类型,指向一个函数(可以保存一个函数的地址),
指向的函数的类型为:
		无返回值,带一个int类型的参数
	    实际上就是指向收到signum后要执行的信号处理函数
		
sighandler_t signal(int signum, sighandler_t handler);

    signum:要捕捉的信号的值
    
    handler:收到signum后的处理方式,有以下三种:
		    1.你自己写一个信号处理函数
			void my_handler(int sig) {
				....
			}
			2.忽略该信号
				SIG_IGN
			3.采用操作系统的默认处理方式
				SIG_DFL
		
    返回值:
	    成功返回上一次的处理方式的函数指针
	    失败,返回SIG_ERR,同时errno被设置
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

// 自定义的信号处理方式
void my_handler(int sig) {
	printf("sig = %d\n", sig);
	printf("haha,you not kill me\n");
}

int main() {
	signal(SIGALRM, my_handler);
	alarm(5);
	while (1);
	return 0;
}

练习:
        通常情况下,一个占用终端的进程在按Ctrl+C的时候会被杀死,现在请写一个代码,这个程序在按 Ctrl+C后不会被杀死

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

// 自定义的信号处理方式
void my_handler(int sig) {
	switch (sig) {
		case SIGALRM:
			printf("recive a SIGALRM\n");
			break;
		case SIGINT: // ctrl + C
			printf("recive a ctrl + C\n");
			break;
	}
}

int main() {
	// 改变信号的处理方式
	signal(SIGALRM, my_handler);
	signal(SIGINT, my_handler);
	// signal(SIGINT, SIG_IGN); // 忽略该信号
	alarm(5);
	while (1);
	return 0;
}

等待信号的到来   pause

等待信号的到来   pause
	
NAME
    pause - wait for signal
SYNOPSIS
    #include <unistd.h>
		
会阻塞调用者进程,直到一个信号处理程序执行完毕后,才会继续运行
int pause(void);		
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

// 自定义的信号处理方式
void my_handler(int sig) {
	printf("recive a signal: %d\n", sig);
	alarm(2);
}

int main() {
	signal(SIGALRM, my_handler);
	alarm(2); // 不会阻塞
	while (1) {
		pause();
		printf("pause is over\n");
	}
	return 0;
}

// 死循环
recive a signal: 14
pause is over
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值