Linux中的进程信号

devtools/2024/10/9 5:19:56/

目录

进程信号

kill/raise/abort

 硬件异常产生信号

由软件条件产生信号

 信号在内核中的表示示意图

pending:

block:

信号集操作函数

sigprocmask


进程信号

信号量和信号不同

信号量的本质是计数器,计数器可以被多进程同时看到。可以对资源进行预定。

所有进程在访问公共资源之前,必须先申请(sem)信号量

必须申请信号量的前提是所有进程必须的看到同一个信号量

信号量本身也是公共资源,所以信号量必须保证自身操作的安全性,++,--都必须是原子操作。

共享内存,消息队列,信号量中均有:

struct ipc_perm {key_t          __key;    /* Key supplied to shmget(2) */uid_t          uid;      /* Effective UID of owner */gid_t          gid;      /* Effective GID of owner */uid_t          cuid;     /* Effective UID of creator */gid_t          cgid;     /* Effective GID of creator */unsigned short mode;     /* Permissions + SHM_DEST andSHM_LOCKED flags */unsigned short __seq;    /* Sequence number */};

结构体的第一个成员的地址,在数字上,和结构体对象本身的地址数字是相等的,虽然类型不同。

进程收到信号时信号不一定会被立即处理,所以进程应有对信号的保存能力(保存在task_struct->收到信号时将对应的位图结构有0->1)。

发送信号的本质就是修改PCB中的信号位图。

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
这两个函数都是成功返回0,错误返回-1。

kill/raise/abort

kill():可以向任意进程发送任意信号

kill xxx x

raise():给自己发送任意信号

raise(x);

abort():给自己发送指定信号SIGABRT

abort();
man 7 signal

Signal      Standard   Action   Comment
  ────────────────────────────────────────────────────────────
       SIGABRT      P1990      Core    Abort signal from abort(3)
       SIGALRM      P1990      Term    Timer signal from alarm(2)
       SIGBUS       P2001      Core    Bus error (bad memory access)
       SIGCHLD      P1990      Ign     Child stopped or terminated
       SIGCLD         -        Ign     A synonym for SIGCHLD
       SIGCONT      P1990      Cont    Continue if stopped
       SIGEMT         -        Term    Emulator trap
       SIGFPE       P1990      Core    Floating-point exception

 硬件异常产生信号

硬件CPU中有mmu内存管理单元,当有越界访问时mmu会异常。OS会识别并向目标进程发送11号信号(野指针)。

由软件条件产生信号

SIGPIPE是一种由软件条件产生的信号

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动
作是终止当前进程。

core为核心转储,当进程出现异常时,将进程在对应时刻,在内存中的有效数据转储到磁盘中----核心转储->可以支持调试。

core-file core.xxx

实际执行信号的处理动作称为信号递达(Delivery)

信号从产生到递达之间的状态,称为信号未决(Pending)。

进程可以选择阻塞 (Block )某个信号。

被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.

注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

 信号在内核中的表示示意图

置于pending表中的信号其状态为未决状态。

pending:

pending位图中,比特位的位置为信号编号,比特位的内容表示是否收到了对应的信号

block:

block位图中,比特位的位置为信号编号,比特位的内容为是否阻塞了对应的信号。

如果一个信号没有被产生,并不妨碍其可以先被阻塞。

task_struct中有字段handler_t handler[32] ,handler数组是有下标的

a.数组的位置(下标),信号的编号。

b.数组下标对应的内容,表示对应信号的处理方法。

sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号 的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有 效”和“无效”的含义是该信号是否处于未决状态。

信号集操作函数

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);

sigprocmask

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 
返回值:若成功则为0,若出错则为-1

#define BLOCK_SIGNAL 2
#define MAX_SIGNUM 31static void show_pending(const sigset_t& pending)
{for(int signo=MAX_SIGNUM;signo>=1;--signo){if(sigismember(&pending,signo))cout<<"1";else cout<<"0";}cout<<"\n";
}int main()
{sigset_t block,oblock,pending;sigemptyset(&block);sigemptyset(&oblock);//sigemptyset(&pending);sigaddset(&block,BLOCK_SIGNAL);sigprocmask(SIG_SETMASK,&block,&oblock);while (true){sigemptyset(&pending);sigpending(&pending);show_pending(pending);sleep(1);}}

0000000000000000000000000000000
0000000000000000000000000000000
^C

0000000000000000000000000000010

一旦对特点信号进行解除屏蔽,一般OS至少立马递达一个信号。

当某一个信号正在被递达期间,同类型信号无法递达!

当当前信号正在被捕捉时,系统会自动将当前信号加入信号屏蔽字。

当信号完成捕捉动作,系统又会自动解除对该信号的屏蔽。

void handler(int signo)
{printf("pid: %d, %d 号信号,正在被捕捉!\n",getpid(),signo);
}
void Count(int cnt)
{while (cnt){printf("cnt: %2d\n",cnt);fflush(stdout);cnt--;sleep(1);}printf("\n");
}
signal(SIGCHLD,handler);printf("父进程, %d, ppid: %d\n",getpid(),getppid());pid_t id=fork();if(id==0){printf("子进程, %d,ppid: %d, exit\n",getpid(),getppid());Count(5);exit(0);}while (1){sleep(1);}

子进程退出时会向父进程发送17号信号。

pid_t ret=waitpid(-1,null,WNOHANG);

非阻塞式的等待子进程退出。

signal(SIGCHLD,SIG_IGN);

子进程自动退出,不会在想父进程发送信号。


http://www.ppmy.cn/devtools/123212.html

相关文章

LINUX——内核移植、内核编译教程

Linux内核编译是一个将内核源代码转换成可在特定硬件架构上运行的二进制文件的过程。以下是编译Linux内核的一般步骤&#xff1a; 1、准备工作&#xff1a; 确保安装了必要的编译工具&#xff0c;如gcc、make、ncurses库&#xff08;用于make menuconfig&#xff09;等。 2、…

【机器学习-无监督学习】降维与主成分分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

查看PyTorch的GPU使用情况的工具

文章目录 torch.cuda APISnapshottorchinfo torch.cuda API torch.cuda.memory_stats&#xff1a;返回给定设备的 CUDA 内存分配器统计信息字典。该函数的返回值是一个统计字典&#xff0c;每个字典都是一个非负整数。torch.cuda.memory_summary&#xff1a;返回给定设备当前内…

docker详解介绍+基础操作 (一)

话不多说&#xff0c;先上干货 配置方法 Ubuntu 14.04/16.04/18.04/20.04/22.04/24.04&#xff08;使用 apt-get 进行安装&#xff09; # step 1: 安装必要的一些系统工具 sudo apt-get update sudo apt-get -y install apt-transport-https ca-certificates curl software-…

Go语言实现随机森林 (Random Forest)算法

在 Go 语言中实现随机森林&#xff08;Random Forest&#xff09;算法通常涉及以下几个步骤&#xff1a; 数据准备&#xff1a;将数据集分为训练集和测试集&#xff0c;确保数据格式适合算法使用。 决策树的构建&#xff1a;随机森林是由多个决策树构成的&#xff0c;首先需要…

大数据毕业设计选题推荐-白酒销售数据分析-Python数据可视化-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

昆虫分类与检测系统源码分享[一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]

昆虫分类与检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Visio…

需求8——通过一个小需求来体会AI如何帮助改bug

这篇文章&#xff0c;我们通过一个简单的例子来说明&#xff0c;平时在写需求的时候&#xff0c;我们可以在什么时候用AI来帮助我们写代码。 首先来看一下这个需求&#xff1a;系统中某个用户使用的时候出现了bug&#xff0c;通过手机建立临时任务报错&#xff0c;没有办法新增…