进程间通信方式--信号

信号(sginal)


信号的定义


信号是linux系统响应某些条件而产生的一个事件,接收到信号的进程会采取相应的措施。通常喜好是因为一个错误产生的。也可以作为进程间通信的一种方式,由一个进程发送给另一个进程。信号的产生叫做生成,接收叫做捕获。
信号的本质


信号是在软件层次上对中断机制的一种模拟,一个进程接收到信号和处理器收到一个中断请求是一样的。
信号是进程间通信机制中唯一的异步通信,进程不需要等待信号的到达,进程也不知道信号到达的时间。
信号的来源
信号的来源主要有两种:
1.硬件来源(按下键盘按键);
2.软件来源,包括kill,raise,alarm等函数;

信号可以直接进行用户空间进程和内核空间进程之间的交互,内核空间的进程可以通过信号来通知用户空间一些系统事件。
如果一个进程没有处在执行态,信号就存放在内核空间中,直到该进程恢复执行。
信号的产生


1.按下终端键
2.硬件异常
3.软件异常
4.调用kill()函数
5.运行kill命令

Linux所支持的信号


信号名 含义 默认操作
SIGHUP 终端挂起或者控制进程终止 终止进程
SIGINT 键盘中断(如break键被按下) 终止进程
SIGQUIT 键盘的退出键被按下 终止进程并进行内核映像转储(dump core)
SIGILL 非法指令 终止进程并进行内核映像转储(dump core)
SIGABRT 由abort(3)发出的退出指令 终止进程并进行内核映像转储(dump core)
SIGFPE 浮点异常 终止进程并进行内核映像转储(dump core)
SIGKILL Kill信号 终止进程,信号不能被捕获,不能被忽略
SIGSEGV 无效的内存引用 终止进程并进行内核映像转储(dump core)
SIGPIPE 管道破裂: 写一个没有读端口的管道 终止进程
SIGALRM 由alarm(2)发出的信号 终止进程
SIGTERM 终止信号 终止进程
SIGUSR1 用户自定义信号1 终止进程
SIGUSR2 用户自定义信号2 终止进程
SIGCHLD 子进程结束信号 忽略信号
SIGCONT 进程继续(曾被停止的进程)
SIGSTOP 终止进程 停止进程,信号不能被捕获,不能被忽略
SIGTSTP 控制终端(tty)上按下停止键 停止进程
SIGTTIN 后台进程企图从控制终端读 停止进程
SIGTTOU 后台进程企图从控制终端写 停止进程

信号的发送


发送信号的函数有:kill()、raise()、sigqueue()、alarm()、setitimer()、abort()。

kill-发送信号给指定进程


函数原型

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int signo);

参数

  • pid:指定发送信号的接收线程,getpid(),表示向自身发信号,等价于raise
  • signo:信号的大小signum

参数pid

参数pid的值 接收信号的进程
pid>0 进程ID为pid的进程
pid=0 同一个进程组中的进程
pid<0 pid!=-1 进程组ID为-pid的所有进程
pid=-1 除发送进程外,所有进程ID大于1的进程

参数signo
Signo是信号值,当为0时(即空信号),实际不发送任何信号,但照常进行错误检查,因此,可用于检查目标进程是否存在,以及当前进程是否具有向目标发送信号的权限(root权限的进程可以向任何进程发送信号,非root权限的进程只能向属于同一个session或者同一个用户的进程发送信号)。

Kill()最常用于pid>0时的信号发送,调用成功返回 0; 否则,返回 -1。


下面程序,完成了父进程和子进程交替输出5次,然后父进程发送信号终止子进程,父进程继续循环输出。

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

int main(int argc, char *argv[])
{
	pid_t pid;
	
	int i = 0;
	
	//创建进程
	pid = fork();
	
	//出错
	if(pid < 0){
		printf("fork process failed!\n");
		exit(1);
	}else if(pid == 0){
		//子进程
		while(1){
			printf("I am child process ,my pid is: %d\n", getpid());
			sleep(3);
		}
	}else{
		//父进程
		while(1){
			printf("I am parent process ,my pid is: %d\n", getpid());
			sleep(3);
			i++;
			if(i == 2){
				kill(pid, SIGINT);
			}
		}
	}
	return 0;
}

在这里插入图片描述
raise-向自己发送信号


向进程本身发送信号,参数为即将发送的信号值。
调用成功返回0;否则,返回-1.
函数原型

#include <signal.h>
int raise(int signo);

下面的程序,进程通过raise向自身发送了一个SIGINT信号。


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

int main(int argc, char *argv[])
{
	int i = 0;
	
	while(1){
		i++;
		if(i ==3){
			printf("I will raise a SIGINT to myself!\n");
			//发送SIGINT给进程自身
			raise(SIGINT);
		}
		//进程正常运行
		printf("I am running!\n");
		sleep(1);
	}
	return 0;
}

在这里插入图片描述
alarm-设置信号传送闹铃

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

专门为SIGALRM信号而设,在指定的时间seconds秒后,将向进程本身发送SIGALRM信号,又称为闹钟时间。

进程调用alarm后,任何以前的alarm()调用都将无效。如果参数seconds为零,那么进程内将不再包含任何闹钟时间。

返回值,如果调用alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。

abort–终止进程


#include <stdlib.h> 
void abort(void);

向进程发送SIGABORT信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数。即使SIGABORT被进程设置为阻塞信号,调用abort()后,SIGABORT仍然能被进程接收。该函数无返回值。

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


int main(void)
{
    printf("Calling abort()\n");
    abort();

    /* The next code will never reach... */
    printf("after abort...\n");

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44715649/article/details/88863533