百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Linux进程间通信——信号(linux进程通信)

ahcoder 2025-03-18 09:40 4 浏览

概念

什么是信号?

  • 信号是linux系统中一种常用的通信机制,A给B发送信号,B在收到信号之前执行自己的代码,收到信号后,不管执行什么程序,都暂停运行,去处理信号,处理完毕后再继续执行原来的程序,是一种软中断。

特点

  • 由于信号是通过软件方法实现的,具有很强的延时性,对用户来讲,时间非常短,不易察觉
  • 每个进程收到的所有信号,都是由内核负责发送,内核处理

与信号相关的事件或者名词

产生信号的基本方法

  • 系统调用当前进程的某些函数
  • 通过命令产生,如kill指令
  • 硬件异常、段错误、内存出错、总线错误
  • 软件条件产生,如alarm定时器
  • 硬件产生,如ctrl+c按键

信号分类及信号一览表

1.可靠信号与不可靠信号

  • 不可靠信号
    Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,信号值小于SIGRTMIN的信号都是不可靠信号,它的主要问题是信号可能丢失。
  • 可靠信号
    随着时间的发展,实践证明了有必要对信号的原始机制加以改进和扩充。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不会丢失

2.指令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
  • Linux提供两个特殊信号:9号和19号信号,无法修改,提供终止进程的手段
  • 写信号时最好使用信号宏名称,因为不同系统下宏的数值可能是不同的,如下有些信号宏可能有多个数值

递达

从信号产生,会先发送给内核,通过内核处理再发送到进程,进程再处理信号这一过程称为递达

未决信号集

从信号产生,还未递达至进程,信号没有被处理掉,这过程中会有一个未决信号集存贮这些信号

阻塞信号集

也叫做信号屏蔽字,每个进程都有一个用来描述哪些信号递送到进程时将被阻塞的信号集,该信号集中的所有信号在递送到进程后都将被阻塞。


假设发送第三个信号,若阻塞信号集第三位为1,那么进程就不会收到该信号,因此未决信号集中第三位将保持状态为1

Linuxc/c++服务器开发高阶视频,电子书学习资料后台私信【架构】获取

内容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,P2P,K8S,Docker,TCP/IP,协程,DPDK多个高级知识点

信号处理方式

  • 系统默认动作,例如ctrl+c将进程杀死
  • 忽略(丢弃)该信号,就象没有收到该信号似的继续运行
  • 捕捉信号,自定义动作

信号相关函数

头文件

  • signal函数
    函数原型:
    typedef void (*sighandler_t)(int);//返回类型为空的函数指针,整型参数
    sighandler_t signal(int signum, sighandler_t handler)
    功能:接收某个信号sig(第一个参数),使程序接收到信号时执行对应函数func(第二个参数),func这个函数必须有一个int类型的参数(即接收到的信号)
    func也可以是下面两个特殊值:
    SIG_IGN 屏蔽该信号
    SIG_DFL 恢复默认行为
  • int kill(pid_t pid, int sig);
    功能:给指定进程发送信号(不一定杀死),第一个参数是进程ID,第二个参数是发送信号的类别,
    返回值:成功返回0, 失败返回-1
  • int sigemptyset(sigset_t *set);
    功能:将某个信号集清0
    返回值:成功返回0, 失败返回-1
  • int sigfillset(sigset_t *set);
    功能:将某个信号置1
    返回值:成功返回0, 失败返回-1
  • int sigaddset(sigset_t *set, int signo);
    功能:将某个信号加入到信号集中
    返回值:成功返回0, 失败返回-1
  • int sigdelset(sigset_t *set, int signo);
    功能:用来将参数signo信号从参数set信号集里删除。
    返回值:成功则返回0,如果有错误则为-1。
  • int sigismember(const sigset_t *set, int signo);
    功能:用来测试参数signo信号是否已加入至参数set信号集里。
    返回值:如果信号集里已有该信号则返回1,否则返回0。错误则为-1
  • int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
    功能:读取或更改进程的信号屏蔽字。
    返回值:若成功则为0,若出错则为-1


参数how的含义

  • int sigpending(sigset_t *set);
    功能: sigpending读取当前进程的未决信号集,通过set参数传出。
    返回值:若成功则为0,若出错则为-1
  • void abort(void);
    头文件:
    功能:向进程发送sigabort信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数。
    说明:即使sigabort被进程设置为阻塞信号,调用abort()后,sigabort仍然能被进程接收。该函数无返回值

讲了这么多,做个例子,主要实现的功能是:打印当前进程未决信号集,并测试屏蔽信号

#include 
#include 
#include 
#include 
#include <sys/time.h>

void printf_ped(sigset_t* ped)
{
	int i;
	for (i = 0; i < 32; i++)
	{
		if (sigismember(ped, i) == 1)
		{
			putchar('1');	
		}
		else
		{
			putchar('0');
		}
	}
	printf("\n");
}

int main(void)
{
	sigset_t myset, oldset, ped_set;

	sigemptyset(&myset);//清空信号集为0
	sigaddset(&myset, SIGQUIT);//添加信号到信号集中

	sigprocmask(SIG_BLOCK, &myset, &oldset); //设置进程的信号屏蔽字

	while (1)
	{
		sigpending(&ped_set);//读取未决信号集到ped_set中
		printf_ped(&ped_set);//打印打印未决信号集
		sleep(3);
	}
	return 0;
}

运行结果如下


一开始没有产生信号 未决信号集都为0,当我们按下crtl+\时产生3号信号,但是由于我们屏蔽了3号信号,未决信号集中第三位一直为1,表示该信号还未被处理

定时器相关函数

头文件 #include <sys/time.h>

alarm函数

  • 每个进程只有一个alarm
  • 无论进程处于何种状态下,定时器都在计时

函数原型:
unsigned int alarm(unsigned int seconds);

功能:专门为sigalrm信号而设,在指定的时间seconds秒后,将向进程本身发送sigalrm信号

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

说明:进程调用alarm后,任何以前的alarm()调用都将无效

setitimer函数

函数原型:
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

参数:
第一个参数 which指定定时器类型
第二个参数 结构itimerval的一个实例
第三个参数 可不做处理,old_value一般设为NULL

结构体类型如下

struct itimerval
 {
        struct timeval it_interval; /* 下一次的取值 */
        struct timeval it_value; /* 本次的设定值 */
};

struct timeval 
{
        long tv_sec; /* 秒 */
        long tv_usec; /* 微秒,1秒 = 1000000 微秒*/
};

功能:这个函数可以周期性计时,定时器将it_value递减到0时,产生一个信号,并将it_value的值设定为it_interval的值,然后重新开始计时,如此往复,若it_interval为0则定时器停止。参数ovalue如果不为空,则其中保留的是上次调用设定的值

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

定时器类型:

itimer_real: 按实际时间计时(系统时间+用户时间+等待时间),经过指定的时间后,内核将发送SIGALRM信号给本进程
itimer_virtual :只计算进程占用cpu的时间,经过指定的时间后,内核将发送SIGVTALRM信号给本进程
itimer_prof :计算占用cpu及执行系统调用的时间,经过指定的时间后,内核将发送SIGPROF信号给本进程

写个例子,每3秒打印一次hello world

#include 
#include 
#include <sys/time.h>
#include 


void myfun(int signo)
{
	printf("hello world\n");
}

int main()
{
	struct itimerval it, oldit;
	int ret;

	signal(SIGALRM, myfun);

	//本次设定值
	it.it_value.tv_sec = 3;
	it.it_value.tv_usec = 0;

	//下次设定值
	it.it_interval.tv_sec = 3;
	it.it_interval.tv_usec = 0;

	ret = setitimer(ITIMER_REAL, &it, &oldit);
	if (ret == -1)
	{
		printf("error\n");
		exit(1);
	}

	while (1);
	return 0;
}

运行结果

相关推荐

ARM64内核内存布局图(ARM64内核内存布局图解)

ARM64架构处理器采用48位物理寻址机制,最大可以寻找到256TB的物理地址空间。对于目前的应用来说已经足够了,不需要扩展到64位的物理地址寻址。虚拟地址也同样最大支持48位支持,所以在处理器的架构...

ARM64 linux 调试串口通信(ARM64 linux 调试串口通信实验报告)

ARM64linux调试串口通信随着国产机普及很多工作也转移到了新平台上,以前调试设备用的笔记本电脑也换成新国产ARM64架构的了。本文以绿联CM204USB-A转RJ45Console调试线...

Gentoo Linux 终止对 Itanium IA-64 体系的支持

GentooLinux是最后几个继续维护Itanium(IA-64)架构构建的Linux发行版之一,但现在这些已停产的英特尔处理器正在逐步淘汰。由于Linux6.7内核放弃了对Itan...

如何检查 Linux 系统是 32 位还是 64 位?这9个命令查的又快又准!

在Linux系统中,位数(bit)通常指的是CPU架构的位宽,即CPU一次能够处理的数据量。32位系统和64位系统在内存寻址能力、计算性能和软件支持上存在显著差异:「32位系统」:...

调出好画面!带你玩转飞凌嵌入式AM62x开发板的显示接口

来源:飞凌嵌入式官网“显示”是嵌入式开发板最为重要的功能之一,能够支持更多种类、更高规格的显示接口,意味着它能够应对的使用场景也更加广泛。每一款嵌入式开发板在出厂前都会做屏幕调试,但在客户的实际项目开...

带你玩转AM62x开发板的显示接口——LVDS的显示和修改方式

此前小编已为大家介绍过OK6254-C开发板的RGB显示和修改方式,今天将继续为大家介绍OK6254-C开发板的LVDS显示和修改方式。话不多说,我们进入正题。1、LVDS接口规格飞凌嵌入式OK62...

AM335x继任者?AM6254性能解析(am2361p)

飞凌嵌入式FET6254-C核心板基于TISitaraTMAM62x系列工业级处理器设计开发,采用ARMCortex-A53架构,主频最高可达1.4GHz;并集成了丰富的接口,可广泛应用于的工...

如何在 Linux 发行版中安装微信和 QQ?

很多人因为工作沟通的原因需要用到微信和QQ,那么如何在Linux发行版中安装微信和QQ呢?以下是一些尝试的解决方法。QQ上一个版本的QQLinux版还是在2009年,而在现在,基于N...

MySQL:物理备份工具XBK(mysql 备份方案)

XBK的优缺点:XBK(PerconaXtraBackup)优点:1.免费2.热备:备份期间不阻塞innodb和XtraDB表,但会阻塞Myisam表3.物理备份:备份恢复快XBK缺点:1.不支持远...

AMD锐龙9 9950X CPU AIDA64跑分曝光:比7950X最高快45%

IT之家6月26日消息,Anandtech论坛网友igor_kavinski本周一发布帖子,分享了AMD旗舰锐龙99950X处理器的AIDA64基准测试跑分,与当前基于Z...

qemu linux内核(5.10.209)开发环境搭建

版本信息宿主机:ubuntu20.04.6LTS(FocalFossa)虚拟机:ubuntu20.04.6LTS(FocalFossa)安装宿主机的步骤省略,和一般的在vmware中安...

iPhone 7成刷机神器,成功运行乌班图、Linux、安卓

在智能机刚开始流行的时候,很多手机发烧友都喜欢刷机,当时民间大神们制作了特别多优化的ROM。后来随着手机硬件的逐步提升,以及厂商们对系统的大力优化,让大家对于刷机的兴趣也越来越少。不知道大家还记得这部...

12 款最佳免费开源 Linux 渲染器 | 火狐浏览器 130.0 版本更新

12款最佳免费开源Linux渲染器Linux的一大优势在于其拥有丰富的开源软件,可以满足艺术家、摄影师、动画师和设计师的需求。凭借价格低廉的硬件、免费的软件以及少量的才能和灵感,任何人都可以创...

Linux中xargs 命令详解与实用场景

xargs是Linux系统中常用的命令行工具之一,它能够从标准输入构造参数列表并传递给其他命令使用,是处理批量数据操作时的重要利器。一、xargs的基本语法xargs[OPTION]...[C...

Linux 磁盘扩容(非LVM)方式(linux扩容lvm磁盘容量)

今天接到一个客户的需求,CentOS的/分区容量太小了,OA系统所有的数据都在这下面,由于当时前同事给客户安装系统时采用了标准分区,而不是LVM逻辑卷,所以不支持在线扩容。df-hT查看磁盘使...