Linux---进程通信(三)---信号通信

本文详细介绍了Linux进程间通信的信号通信方式,包括信号的基本概念、使用方法和相关函数,如kill、raise、alarm等,并通过实例展示了如何在C语言中应用这些函数实现信号的发送和处理。此外,还探讨了信号处理函数signal的使用,以及信号在父子进程通信中的作用。
摘要由CSDN通过智能技术生成

系列文章目录

文章一: Linux—进程通信(一)—进程通信概述
文章二: Linux—进程通信(二)—管道
文章三: Linux—进程通信(三)—信号通信
文章四: Linux—进程通信(四)—IPC通信之共享内存
文章五: Linux—进程通信(五)—IPC通信之消息队列
文章六: Linux—进程通信(六)—IPC通信之信号灯



前言

本文主要讲解了进程通信的信号通信方式
给出了信号通信所需要的各种操作函数
同时基于Linux系统给出了C语言代码的例子


一、信号通信是什么?

信号通信是进程之间通过信号来互相传递信息的通信方式,信号由内核来发送,用户空间不能发送信号。

区别于管道:

1.信号是已经在Linux内核中存在的对象
2.内核中存在着多个信号
3.信号本身不能改变,但是得到信号的“反应”可以根据需求而改变。

可以通过以下的Linux命令可以查看信号的具体信息:

kill  -l

结果为:
在这里插入图片描述

1.数子代表每种信号的ID号。
2.名字代表信号的意义。
3.总共有64中信号。

二、信号的使用

1.信号的应用举例

在LInux系统中有如下杀死指定进程的命令:

kill  9   进程的pid号

这里的pid号可以通过如下命令查看:

ps  -axj
执行如上命令后,pid号就在第二列。

这个命令的原理就是根据信号通信实现的,其中9代表Linux内核中的第9个信号,根据上面的图可以发现该信号是“SIGKILL”。

2.信号通信的函数

信号发送函数kill

函数原型:

int kill(pid_t pid,int sig);

所需头文件:

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

函数参数:

1.第一个参数是pid:
		正数:要接收信号的进程的进程号
		0:信号被发送到所有和此进程在同一进程组的进程
		-1:信号发送给所有进程表中的进程(除了进程号最大的进程)
2.sig:信号的ID

函数返回值:

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

例子1:实现Linux的kill命令

#include<sys/types.h>
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
	int sig;
	int pid;
	if(argc<3)
	{
		printf("please input param\n");
		return -1;
	}
	sig=atoi(argv[1]);
	pid=atoi(argv[2]);
	printf("sig=%d,pid=%d\n",sig,pid);

	kill(pid,sig);
	
	return 0;
}

信号的发送函数raise

函数原型:

int raise(int sig);

所需头文件:

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

函数功能:

发信号给自己
相当于:kill(getpid(),sig);

参数:

1.sig:信号的ID

返回值:

成功返回0,失败返回-1

注意:

raise(9);终止进程时,调用的是_exit(),不会将库缓存刷入内核空间。

例子2:raise函数的示例

#include<sys/types.h>
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
	printf("raise before\n");
	raise(9);
	printf("raise after\n");
	return 0;
}

执行结果:

raise before打印,raise after不打印,即进程被终止。同时还会打印进程被终止的信息。

信号发送函数alarm

首先要了解一个信号:

信号信号代表的意义默认操作
SIGALRM该信号是当一个定时器到时的时候发出终止进程

函数原型

unsigned int alarm(unsigned int seconds);

所需头文件:

#incldue<unistd.h>

函数功能:

1.只会发送SIGALRM信号给当前进程。
2.alarm函数会让内核定时一段时间后发送该信号

函数参数:

seconds:指定秒数

函数返回值:

1.成功一般返回0,失败一定返回-1
2.如果进程在调用alarm前设置了闹钟时间,则成功会返回上一个闹钟时间剩余的时间。

例子3:闹钟信号杀死进程

#include<sys/types.h>
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
	int i;
	i=0;
	printf("alarm before\n");
	alarm(9);
	printf("alarm after\n");
	while(i<20)
	{
		i++;
		sleep(1);
		printf("process things %d\n",i);
	}
	return 0;
}

执行结果:

i的值是8的时候会接着打印“Alarm clock”,进程被杀死

信号的接收方法

信号的接收可以用以下的三种方式:

1.pause()
2.sleep()
3.while(1)

这里我们重点介绍pause()函数
函数原型;

int pause(void);

所需头文件:

#incldue<unistd.h>

函数功能:

让进程处于睡眠状态,即S状态

函数的返回值:

成功返回0,失败返回-1

信号的处理函数signal

我们要明确:

1.之前我们没有采用signal函数,系统会采用默认的信号处理方式。
2.默认处理方式一般是终止进程,有些是睡眠进程,也有些是忽略信号。

接下来我们要介绍signal函数:
函数原型:

//返回值是函数指针
//第二个参数也是一个函数指针
void(*signal(int signum,void(*hander)(int)))(int);

所需头文件:

#include<signal.h>

函数的参数:

1.signum:指定信号
2.hander:
		SIG_IGN:忽略该信号
		SIG_DFL:采用系统默认的方式处理信号
		自定义信号处理函数的函数指针

函数的返回值:

1.成功:设置之前的那个信号处理函数的函数指针
2.失败:返回-1

例子4:signal函数的使用

#include<sys/types.h>
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
void myfun(int signum)
{
	int i=0;
	while(i<10)
	{
		printf("process signal signum=%d",signum);
		sleep(1);
		i++;
	}
	return;
}
int main()
{
	int i;
	i=0;
	//14号信号是alarm所发送的信号
	signal(14,myfun);
	printf("alarm before\n");
	alarm(9);
	printf("alarm after\n");
	while(i<20)
	{
		i++;
		sleep(1);
		printf("process things %d\n",i);
	}
	return 0;
}

执行结果:

1.先打印main函数的信息到i=8的那条语句。
2.然后程序跳到myfun函数执行10条打印语句。
3.然后回到main函数继续执行完之后的打印语句。

例子5:以父子进程的方式进行信号通信

#include<sys/types.h>
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
void myfun(int signum)
{
	int i=0;
	while(i<5)
	{
		printf("recive signum=%d",signum);
		sleep(1);
		i++;
	}
	return;
}
void myfun1(int signum)
{
	printf("recive signum=%d",signum);
	//wait函数是等待子进程结束,功能用来回收僵尸进程的资源
	wait(NULL);
	return;
}
int main()
{
	pid_t pid;
	pid=fork();
	if(pid>0)
	{
		int i=0;
		signal(10,myfun);
		signal(17,myfun1);
		while(1)
		{
			printf("parent process things,i=%d\n",i);
			sleep(1);
			i++;
		}
	}
	if(pid==0)
	{
		sleep(10);
		/*
		getppid()是获得父进程的pid号
		10号是SIGUSR1信号,是用户自定义信号
		*/
		kill(getppid(),10);
		sleep(10);
		exit(0);
		//包含一个发送信号函数
		//kill(getppid(),17);		
	}
	return 0;
}

总结

多线程编程也有信号通信,感兴趣的可以看:
Linux—多线程编程(二)—多线程的控制

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SigmaBull

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值