linux远程开发——信号的使用(信号绑定和发送)

目录

一、信号的概念

二、signal()库函数

三、kill()函数

1、函数作用

2、函数原型

四、可靠与不可靠信号

五、总结


一、信号的概念

        信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动,信号是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等。它们由shell和终端管理器产生以引起中断。信号的目的是为了通知做某件事,就比如早上的闹钟通知你起床,闹钟就起到一个信号的作用。

在linux下可以通过 kill -l 查看所有的信号

        之前提到过通过 kill -9 进程ID,可以把该ID所属的进程结束掉。学习了信号这个概念,可以将这条命令理解为发送第9个信号给该ID所属的进程,通知他去做某件事。通过上图所示第9个信号为SIGKILL,也就是发送停止进程的信号给该ID所属的进程,通知它停下来,也就是所谓的“杀死”进程。

        编号为1-31的为不可靠信号,34-64的为可靠信号。连续不间断发送信号,信号会丢失的为不可靠信号,连续不间断发送信号,信号不会丢失的为可靠信号

二、signal()库函数

        如果想让程序能够处理信号,可以使用 signal库函数,要引入头文件<signal.h>。在linux终端下输入命令 man signal来查看他的函数原型

        可以看到,signal()函数的第一个参数signum是信号编号,也就是 kill -l 能够查询到的所有信号,第二个参数sighandler是一个函数指针。

        准备捕捉或屏蔽的信号由参数signum给出,接收到指定信号时将要调用的函数由sighandler给出。sighandler这个函数必须有一个int类型的参数(即接收到的信号代码),函数本身的类型是void,sighandler也可以是下面两个特殊值:SIG_IGN(屏蔽该信号),SIG_DFL (恢复默认行为)。

        通俗的说signal()库函数的作用是将某个信号和某个函数绑定起来,当这个信号被发送出来,就去做绑定的这个函数的业务。Qt的信号与槽机制就是通过借鉴这种方式来实现的。

三、kill()函数

1、函数作用

        kill函数的作用是把参数sig给定的信号发送给标识号为pid的进程。如果该信号通过sinal()和某个函数绑定起来,那么就暂时中断这个进程,去做绑定的这个函数的业务,做完这个函数的业务,进程继续运行。

        要想发送一个信号,发送者进程必须拥有相应的权限。这通常意味着两个进程必须拥有同样的用户ID。

2、函数原型

int kill(pid_t pid, int sig);

参数:

pid:进程ID

sig:某个信号

返回值:

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

四、可靠与不可靠信号

下面通过一段代码来验证可靠信号和不可靠信号

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

void signalfunction(int i);

int main()
{
	int pid = 0;
	int status = 0;
	//将信号和函数绑定在一起
	signal(SIGUSR1, signalfunction);
	pid = fork();
	if (pid == 0)//子进程
	{
		while(1)
		{
			cout << "子进程运行中 pid = " << getpid() << endl;
			sleep(1);
		}
	}
	else if(pid > 0)//父进程
	{
		sleep(3);//先让子进程先处理业务,测试kill函数
		for (int i = 1; i <= 5; i++)
		{
			cout << "父进程给子进程发送第 " << i << " 个信号" << endl;
			kill(pid, SIGUSR1);//给子进程发送信号
		}
		sleep(3);//延时3秒
		kill(pid, SIGKILL);//给子进程发送停止信号
		waitpid(pid, &status, 0);//等待子进程结束,防止子进程托孤
		cout << "子进程结束" << endl;
	}
	return 0;
}

void signalfunction(int i)
{
	cout << "函数被调用了 i = " << i << endl;
}

        编号为10的信号(SIGUSR1)和编号为12的信号(SIGUSR2)都是用户信号,程序员可以使用他,同时这两个信号都是不可靠信号。

        上面的这段代码父进程通过一个for循环循环发送5次信号(SIGUSR1),而该信号(SIGUSR1)通过signal(SIGUSR1, signalfunction)和signalfunction()函数绑定起来,也就是说发送一次信号就会调用一次这个signalfunction()函数。控制台输出如下:

        可以发现父进程发送了5次信号,可是绑定的函数才执行一次,也就是出现了信号丢失的现象,印证了:连续不间断发送信号,信号会丢失的为不可靠信号,编号为1-31的都是不可靠信号。同时可以发现调用的函数打印的int类型的值正好是该不可靠信号(SIGUSR1)的编号10

        如果将signal(SIGUSR1, signalfunction)改为signal(SIGRTMIN, signalfunction),发送信号kill(pid, SIGUSR1)改为kill(pid, SIGRTMIN)来继续测试,控制台输出如下:

        可以发现父进程发送了5次信号,绑定的函数也执行了5次,也就是信号并没有丢失,印证了:连续不间断发送信号,信号不会丢失的为可靠信号,编号为34-64的都是可靠信号。调用的函数打印的int类型的值也正好是该可靠信号(SIGRTMIN)的编号34

五、总结

1、signal()函数可以将某个信号和某个函数绑定起来。

2、kill()函数可以发送某个信号给某个ID的子进程,并暂时中断该子进程,转去处理这个信号通过signal()函数绑定的函数业务。

3、编号为1-31的都是不可靠信号,34-64的都是可靠信号。连续不间断发送信号时不可靠信号会出现信号丢失的现象,而可靠信号不会出现这个现象。

原创不易,转载请标明出处。

对您有帮助的话可以点赞收藏+关注,会持续更新的(嘻嘻)。

猜你喜欢

转载自blog.csdn.net/wmcy123/article/details/123587709