Linux信号集、信号的阻塞&信号驱动

一、信号集

信号的三种方式,即使是忽略,也仍然打断了进程的进行(相当于是捕捉了信号,执行的了空函数什么都没做),可如果在访问重要资源时不希望被打断呢?

可以用阻塞 ,即产生了信号却没及时送达到进程 ,它处于未决状态 ,并不是不响应该信号,而是推迟响应

信号的状态

  • 递达delivery:信号产生并递达到进程

  • 未决pending:信号产生但未递达到进程,主要是阻塞屏蔽导致的,SIGKILL、SIGSTOP不可阻塞

Linux内核的进程控制块 PCB 是一个结构体task_struct, 除了包含进程 id,状态,工作目录,用户 id,组 id,文件描述符表,还包含了信号相关的信息,主要指阻塞信号集和未决信号集,信号集中每个bit位对应一个信号

阻塞信号集mask:信号对应的比特位置1,即被阻塞屏蔽,信号将处于未决状态,屏蔽解除后才能递达

未决信号集pending:信号产生时,未决信号集中描述该信号的位置1表示未决(相当于别人给你发送了一个消息未读),当信号被处理后,该位置0(相当于消息已回)

因此可以通过设置阻塞信号集的这些bit位来决定是否阻塞

信号集有关的操作函数

cpp 复制代码
sigset_t set;               //信号集结构体变量  相当于设置了一个信号集
sigemptyset(sigset_t *set)  //清空信号集
sigfillset(sigset_t *set)   //信号全添加进信号集
sigaddset(sigset_t *set, int signum) //指定信号添加到信号集
sigdelset(sigset_t *set, int signum) //指定信号从信号集合中删除
sigismember(sigset_t *set, int signum) //判断一个信号是否在集合中

int sigprocmask(int how, sigset_t *set, sigset_t *oset)
功能:将进程中的信号阻塞集替换成定义好的信号集set,并根据how决定是否阻塞信号
@param: how SIG_BLOCK   置1
    		SIG_UNBOLCK 置0
    		SIG_SETMASK 信号集设置为参数set中的信号
    	set 设置的信号集  oset 一般给NULL即可
@return: 成功返回0失败返回-1

示例:

cpp 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>


void handler(int signum)
{
	if(signum == SIGINT)
	{
		printf("i caught SIGINT,i won't stop\n");
	}


}


int main()
{

        struct sigaction act;
        act.sa_handler = handler;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
	sigaction(SIGINT,&act,NULL);

	//block signal for a while and unblock
	sigset_t set;
	sigemptyset(&set);
	sigaddset(&set,SIGINT);
	sigprocmask(SIG_BLOCK,&set,NULL);
	sleep(5);
	sigprocmask(SIG_UNBLOCK,&set,NULL);

	while(1)
	{
		sleep(1);
	}

	return 0;
}

二、信号驱动

cpp 复制代码
int pause(void)
功能:暂停当前进程,进入休眠状态,直至收到任意信号处理完才会返回,所以可以用作信号驱动
  • 信号被忽略时,进程继续挂起暂停
  • 信号被默认终止处理时,则进程直接终止退出
  • 信号被捕捉处理,则处理完后返回-1,继续往下运行
  • 信号从屏蔽->解除屏蔽,进程仍挂起暂停,pause感受不到这个信号的产生和处理,因为在解除屏蔽的瞬间就信号抵达就处理完了,这种情况下要用sigsuspend
cpp 复制代码
int sigsuspend(sigset_t *sigmask)
功能:将进程的阻塞信号集替换成sigmask信号集,然后暂停进程,相当于sigprocmask + pause的结合体,适合用于解除信号屏蔽的同时驱动

示例:

cpp 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>


void handler(int signum){ }

void task(void)
{
	puts("task start");
	sleep(5);
	puts("task end");
}

int main()
{

        struct sigaction act;
        act.sa_handler = handler;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
	sigaction(SIGINT,&act,NULL);
	
	sigset_t set,set1;
	sigemptyset(&set);
	sigemptyset(&set1);
	sigaddset(&set,SIGINT);

	pause();

	while(1)
	{
		sigprocmask(SIG_BLOCK,&set,NULL);
		task();
		sigsuspend(&set1);
	}

	return 0;
}
相关推荐
一叶龙洲12 小时前
win11与Ubuntu之间同步配置、插件
linux·运维·ubuntu
谙弆悕博士12 小时前
系统集成项目管理工程师教程(第3版)笔记——第2章:信息技术发展
笔记·计算机网络·信息安全·学习方法·业界资讯·软考·系统分析师
世人万千丶12 小时前
鸿蒙Flutter TextStyle样式配置
学习·flutter·harmonyos·鸿蒙
CHANG_THE_WORLD13 小时前
12.总结:深入理解 Linux I/O 多路复用:select、poll、epoll 全解析
linux·运维·服务器
吃着火锅x唱着歌13 小时前
Effective C++ 学习笔记 条款37 绝不重新定义继承而来的缺省参数值
c++·笔记·学习
风曦Kisaki13 小时前
# Linux笔记:操作系统优化与资源管理
linux·运维·服务器·笔记
小弥儿13 小时前
GitHub今日热榜 | 2026-07-19
人工智能·学习·github·知识图谱
阿米亚波14 小时前
【C++】流式数据输入处理(不完全整理)
开发语言·c++·笔记
Mr.HeBoYan14 小时前
一次持续三天才出现的丢包故障——深入解析 DPDK Memory Ordering、rte_ring 与 CPU Memory Barrier (下)
linux·网络·算法·架构·dpdk
zhangrelay15 小时前
笔记本轻量高品质延寿工具完整分系统清单
运维·笔记·学习