[Linux]信号处理

本文探讨了操作系统中信号作为进程间通信手段的重要概念及代码示例。
摘要由CSDN通过智能技术生成

在操作系统中,信号是一种进程间通信的机制,用于通知进程发生了某个特定事件。进程可以识别并处理不同的信号,以执行相应的操作。以下是关于信号的一些重要概念和相关代码示例:

进程对信号的处理能力
1.信号的处理能力是进程内置的一部分。 进程必须识别并能够处理信号。即使信号没有直接产生,进程也要具备处理信号的能力。

2.进程即便是没有收到信号,也能知道哪些信号该怎么处理。 进程可以预先定义对不同信号的处理方式,即使在信号产生之前,进程也已经知道如何处理这些信号。

3.进程可能并不会立即处理收到的信号。 当进程真的收到了一个具体的信号时,它可能不会立即处理这个信号,而是在合适的时机进行处理。

4.一个进程必须当信号产生,到信号被处理,就一定会有时间窗口,进程具有临时保存哪些信号已经发生了的能力。

前台进程:执行./的程序(linux每次登录只允许一个前台进程运行)谁获取键盘输入,谁是前台进程
后台进程:在./xxx运行程序的时候 加上& 可以在执行程序时继续使用指令,变成了后台进程,你输入的指令都是给bash的,所有ctrl+c没办法停止

kill一共又62个信号,1-31为普通信号,34-64为实时信号;

SIGHUP (1): 终端挂起或控制进程终止。
SIGINT (2): 中断信号,通常由 Ctrl+C 产生。
SIGQUIT (3): 退出信号,通常由 Ctrl+\ 产生。
SIGILL (4): 非法指令。
SIGTRAP (5): 跟踪/断点陷阱。
SIGABRT (6): 异常终止。
SIGBUS (7): 总线错误。
SIGFPE (8): 浮点异常。
SIGKILL (9): 强制终止。
SIGUSR1 (10): 用户自定义信号1。
SIGSEGV (11): 段错误。
SIGUSR2 (12): 用户自定义信号2。
SIGPIPE (13): 向无读进程的管道写入。
SIGALRM (14): 定时器到期。
SIGTERM (15): 终止信号。
SIGSTKFLT (16): 协处理器栈错误。
SIGCHLD (17): 子进程终止或停止。
SIGCONT (18): 继续执行已停止的进程。
SIGSTOP (19): 停止进程。
SIGTSTP (20): 交互停止信号。
SIGTTIN (21): 后台进程尝试读取控制终端。
SIGTTOU (22): 后台进程尝试写入控制终端。
SIGURG (23): 紧急条件发生。
SIGXCPU (24): 超时软限制。
SIGXFSZ (25): 超出文件大小限制。
SIGVTALRM (26): 虚拟定时器到期。
SIGPROF (27): 计时器到期。
SIGWINCH (28): 窗口尺寸调整。
SIGIO (29): 异步 I/O 事件。
SIGPWR (30): 电源失效。
SIGSYS (31): 非法系统调用。

信号的相关代码示例
信号的基本操作

SIGNAL(2): 获取当前handler表
#include <signal.h>
typedef void(*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signum:信号编号
handler:自定义的动作
(只需要设置一次,往后都有效)

signal(2,SIG_IGN);忽略2号信号
signal(2,SIG_DFL);终止信号

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

// 定义信号处理函数
void sig_handler(int signo) {
    if (signo == SIGINT) {
        printf("Received SIGINT signal\n");
        exit(0);
    }
}

int main() {
    // 注册 SIGINT 信号处理函数
    signal(SIGINT, sig_handler);
    //signal(2,sig_handler);

    while (1) {
        // 进程执行其他任务
        sleep(1);
    }

    return 0;
}

上述代码演示了如何注册一个信号处理函数,以处理接收到的 SIGINT 信号(通常由 Ctrl+C 产生)。

进程控制相关操作
KILL(2):
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid,int sig);

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>

int main() {
    pid_t child_pid;

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

    if (child_pid == 0) {
        // 在子进程中执行一些操作
        printf("Child process executing\n");
        sleep(2);
    } else if (child_pid > 0) {
        // 在父进程中等待一段时间
        sleep(5);
        // 向子进程发送 SIGTERM(15) 信号
        kill(child_pid, SIGTERM);
    }

    return 0;
}

上述代码创建了一个父进程和一个子进程,父进程在等待一段时间后向子进程发送 SIGTERM 信号。这展示了父进程如何控制子进程的行为。

信号集的操作
sigset_t类型是位图类型 必须配合提供的接口使用
#include <signal.h>
int sigemptyset(sigset_t* set); 清空信号集 全部置零
int sigfillset(sigset_t* set); 全部置1
int sigaddset(sigset_t* set, int signo);添加一个特定的信号
int sigdelset(sigset_t* set, int signo);在特定的信号集中去除
int sigismember(const sigset_t* set, int signo);判断一个信号是否在信号集中

sigprocmask:可读取或更改进程的信号屏蔽字(阻塞信号集) (信号屏蔽字:block信号集)
#include <signal.h>
int sigprocmask(int how,const sigset_t* set, sigset_t * oset);成功为0,失败返回-1
how:此参数指定如何更改信号掩码。它可以取以下值之一:
SIG_BLOCK:将集合中的信号添加到当前信号掩码。 mask = mask | set
SIG_UNBLOCK:从当前信号掩码中移除集合中的信号。 mask = mask & ~set
SIG_SETMASK:将信号掩码设置为 set 参数中指定的值。mask = set
set:指向新信号掩码的指针。此集合中指定的信号将根据 how 参数的值受到影响。
oset:如果此参数不是 NULL,则函数调用之前的当前信号掩码将存储在 oset 指向的位置。

#include <stdio.h>
#include <signal.h>

int main() {
    // 创建并初始化信号集
    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGUSR1);

    // 将信号集添加到当前进程的信号屏蔽字(阻塞信号集)中
    sigprocmask(SIG_BLOCK, &sigset, NULL);

    // 在这里执行其他任务,期间阻塞了 SIGUSR1 信号

    // 从信号屏蔽字中移除 SIGUSR1 信号
    sigprocmask(SIG_UNBLOCK, &sigset, NULL);

    return 0;
}

上述代码展示了如何使用信号集进行信号的阻塞和解除阻塞操作,以控制哪些信号可以被当前进程处理。

信号处理和子进程管理

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

// SIGCHLD 信号处理函数
void sigchld_handler(int signo) {
    if (signo == SIGCHLD) {
        printf("Received SIGCHLD signal\n");
    }
}

int main() {
    // 注册 SIGCHLD 信号处理函数
    signal(SIGCHLD, sigchld_handler);
    //SIGCHLD:表示子进程状态改变。通常,当一个子进程终止或停止运行时,父进程会收到 SIGCHLD 信号,以通知父进程有关子进程状态的变化。
    pid_t child_pid;

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


    //signal(17,SIG_IGN);将SIGCHLD信号,设置为SIG_IGN,这样fork出来得子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。

SIGPENDING(2):
#include <signal.h> 获取当前pending表
int sigpending(sigset_t* set);返回值为 0 表示成功,-1 表示失败
set(输出型参数):指向 sigset_t 类型的指针,用于存储当前未决信号的集合。

  • 42
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值