Linux进程信号

文章目录

一.信号的产生

  • 进程信号:进程在执行任务的过程中,由于某些硬件或软件行为,使操作系统接收到了中断信号,之后操作系统会将经过处理的信号发送给正在运行的进程,收到操作系统信号的进程将中断代码执行流,对信号进行响应

二.Linux内核中进程信号的保存

  • 如果当操作系统给进程发送的信号没有被立即处理时,该信号可以存储在进程的task_struct中,进程的task_struct中有两个用于记录信号相关信息的位图,以及一张用于记录信号处理方法的handler函数指针列表:
  • handler函数指针列表中的元素定义:
    • typedef void (*__sighandler_t)(int);
  • 用户对block位图和pending位图的读取及修改操作统一由一系列系统调用接口来完成
cpp 复制代码
#include <signal.h>
typedef struct {
	unsigned long sig[_NSIG_WORDS];
} sigset_t;//内核中信号位图的定义

//操作信号位图的相关系统调用接口
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);
  • 接口的功能可通过man系统编程手册查询

三.进程信号的捕捉

进程的用户态和内核态

  • 进程地址空间中存在用户空间(用户进程使用的内存资源)和内核空间(操作系统使用的内存资源),用户进程默认处于用户态,此时进程无法以任何形式访问操作系统的资源,当用户进程执行系统调用或捕捉系统信号时,会暂时陷入内核态,对操作系统的资源进行限制性访问.

    • 用户态进程:处于用户态的进程不能访问内核空间中的资源
    • 内核态进程:处于内核态的进程可以访问内核空间中的资源
  • CPU中存在专门用于记录指令执行流用户态和内核态的寄存器字段

进程捕捉操作系统信号的过程

  • 用户的自定义信号处理方法是在用户态之下执行的,这样设计的目的是为了保护操作系统及计算机系统的安全(内核态执行流拥有很高的硬件和软件访问权限)

四.基于信号自定义处理进行进程等待

  • 一对父子进程中,当子进程退出时,会向父进程发送17号信号SIGCHLD,进程等待接口根据该信号对退出的子进程进行资源回收.
  • 因此可以基于信号自定义处理函数进行进程等待,在父进程中自定义信号SIGCHLD的处理函数,在函数中调用进程等待系统接口,这样一来父进程就无需以阻塞或者是非阻塞轮询的方式等待子进程了
cpp 复制代码
#include <iostream>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
void handler(int signo)
{
    std :: cout << "get a signal,signal num:" << signo << std :: endl;
    pid_t rid;
    //对所有已退出的子进程进行非阻塞轮询等待
    while ((rid = waitpid(-1, nullptr, WNOHANG)) > 0){
        std::cout << "I am proccess: " << getpid() << " catch a signo: " << signo << "child process quit: " << rid << std::endl;
    }
} 

int main()
{
    //对信号17进行自定义捕捉(否则由操作系统内核默认方法对信号进行处理)
    signal(SIGCHLD,handler);
    //创建10个子进程,10个子进程都是5秒后退出
    for (int i = 0; i < 10; i++){
        pid_t id = fork();
        if (id == 0){
            std :: cout << "I am child process: " << getpid() << ", ppid: " << getppid() << std::endl;
            sleep(5);
            break;
            std::cout << "child quit!!!" << std::endl;
            exit(0);
        }
        sleep(1);
    }
    //父进程只有在收到信号后才调用进程等待接口
    while(true){
        std :: cout << "MainprocessRunning : " << getpid() << std :: endl;
        sleep(1);
    }
    return 0;
}


相关推荐
Android系统攻城狮11 小时前
Linux FFmpeg深度解析之avcodec_flush_buffers调用流程与实战(十九)
linux·运维·服务器·ffmpeg·车载音视频·ffmpeg音视频进阶
水饺编程12 小时前
第2章:Linux 基础,解压缩【.tar.bz2】压缩包文件
linux·c语言·汇编
Zevalin爱灰灰12 小时前
Linux入门第二部分(ARM裸机篇) 第二章 Cortex-A7 MPCore架构与ARM汇编基础
linux·汇编·arm开发·嵌入式
倔强的石头10612 小时前
【Linux指南】进程通信系列(七):System V 信号量 —— 同步互斥的内核原语
linux·运维·服务器
GeW12 小时前
从"补短板"到"强优势"Linux与数据库认证成为产业跃迁人才支点
linux·数据库
PellyKoo14 小时前
【Ubuntu】GTX 1080 Ti 显卡占用为0但功率高达60W的排查与解决
linux·运维·ubuntu
Fruiticecake15 小时前
epoll 回显服务器是怎么工作的:从 accept 队列到就绪链表,以及它和 select / poll 的区别
linux
承渊政道16 小时前
Linux网络学习【从NAT与代理服务理解网络转发、探索内网穿透原理、再到认识DNS与ICMP、最后动手部署并测试内网穿透】
linux·网络·学习·内网穿透·dns·nat
重生之小比特16 小时前
【Linux系统】17 库制作与原理(下)
linux·运维·服务器
weixin_4509072816 小时前
[ZYNQ Linux] VCU使用
linux·zynq