操作系统-信号(二)

信号的传递与处理

当一个信号被发送时,他将会被发送到目标进程的内核层中,在内核层中有未决信号集和屏蔽集。未决信号集中的信号是指已经发送到进程但还未被处理的信号,而“未决”这个词则表示该信号正在等待处理,这是对应信号设置为1时的情况。当接收到信号但未决信号集对应的位是0,那么系统就会将该位置1,等到信号开始处理再变回0。

当未决信号集是1时,如果是标准信号,不会进行排队,后面的信号将会被丢弃。如果是实时信号,将会按照顺序存入一个队列,当前面的那个信号处理完了,队列首部的信号将会被执行。依次直到全部执行完,这也是为什么被称为可靠信号的原因。

因为标准信号的行为一般都是终止之类的,所以也不需要重复执行好几个,而实时信号一般是自定义的行为,根据需要可能得执行多次。

一种特殊情况,当第一个标准信号走过屏蔽集后,变为递达态开始处理,此时对应的未决信号集变为0,第二个标准信号这个时候过来,这个时候系统会将屏屏蔽集临时置1,暂时屏蔽第二个信号,使其进入到阻塞状态,等到第一个信号处理完毕后,在开始处理第二个信号。也产生了排队的假象。

信号的捕捉函数的执行

首先用户层的代码中执行发送信号的操作,那么信号将会从用户发送到内核层,在这之中发生了层级转换。

信号也是中断,那么内核层可能就会出现中断,内核层就需要处理中断或者处理异常。

当系统的事情都处理完了,先检测是否有未递送的信号。

检测完毕后,开始处理信号。

为了不那么频繁切换层级,系统保留高CPU权限,执行用户层捕捉函数(此时仍是内核层)

处理完捕捉函数后,返回到函数调用位置。

然后发生层级转换,回到用户空间。

继续执行信号后面的程序。

信号处理僵尸进程

当子进程结束的时候,将会告诉操作系统自己结束了,然后操作系统给父进程发送一个SIGCHLD信号,代表子进程已经结束(默认动作是忽略),我们可以将这个信号的捕捉函数设置为回收子进程的函数,这样就可以在子进程结束的时候及时回收了。

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

void signalHandler(int signum) {
    if (signum == SIGCHLD) {
        int status;
        pid_t pid;

        // 等待子进程退出,并获取退出状态
        while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
            if (WIFEXITED(status)) {
                std::cout << "Child process " << pid
                          << " exited with status: " << WEXITSTATUS(status) << std::endl;
            } else if (WIFSIGNALED(status)) {
                std::cout << "Child process " << pid
                          << " terminated by signal: " << WTERMSIG(status) << std::endl;
            }
        }
    }
}

int main() {
    pid_t childPID;

    // 设置SIGCHLD信号处理函数
    signal(SIGCHLD, signalHandler);

    // 创建子进程
    childPID = fork();

    if (childPID >= 0) { // fork成功
        if (childPID == 0) { // 子进程
            std::cout << "Child process" << std::endl;
            sleep(2);
            std::cout << "Child process exiting" << std::endl;
            return 0;
        } else { // 父进程
            std::cout << "Parent process" << std::endl;
            while (true) {
                sleep(1);
            }
        }
    } else { // fork失败
        std::cerr << "Fork failed" << std::endl;
        return 1;
    }

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值