进程间通讯-信号

介绍

进程间通信(IPC)通过信号是一种系统中实现简单、快速通信的方式。以下是一些关于信号在进程间通信中的关键要点:

  1. 信号的目的

    • 异常处理:信号主要用于响应特定的系统事件或错误条件,如除以零、无效内存引用、文件结束等。
    • 进程控制:信号也可以用于控制进程的行为,例如请求进程停止(SIGTERM)、强制进程停止(SIGKILL)、请求进程暂停(SIGSTOP)或恢复执行(SIGCONT)等。
  2. 信号的特点

    • 异步:信号的发送和接收是异步的,即发送信号的进程不需要等待接收信号的进程的响应。
    • 简单:信号不携带大量的信息,通常只是一个信号编号。
    • 默认行为:每个信号都有一个默认的行为,如果进程没有特别设置对某个信号的处理方式,系统会按照默认行为来处理。
  3. 信号列表

    • SIGINT:当用户按下 Ctrl+C 组合键时,会向前台进程发送 SIGINT 信号,通常用于终止进程。
    • SIGTERM:该信号用于请求进程终止。与 SIGINT 不同,SIGTERM 信号可以被进程捕获并处理,以实现进程的优雅退出。
    • SIGKILL:该信号用于强制终止进程。与 SIGTERM 不同,SIGKILL 信号不能被进程捕获或忽略,一旦收到该信号,进程将立即终止。
    • SIGSTOP:该信号用于暂停进程的执行。当进程收到 SIGSTOP 信号时,它将停止执行,直到收到 SIGCONT 信号为止。
    • SIGCONT:该信号用于继续执行被 SIGSTOP 信号暂停的进程。
      除了以上常见的信号外,还有许多其他类型的信号,用于处理不同的进程间通信需求。需要注意的是,不同的操作系统可能对信号的支持和处理方式有所不同。
  4. 信号的生成和发送

    • 信号可以由系统自动产生,如硬件异常、软件错误或者用户通过键盘输入(如Ctrl+C)。
    • 进程也可以通过调用 kill()raise() 等系统函数主动发送信号给其他进程或自身。
  5. 信号的捕获和处理

    • 进程可以注册一个信号处理函数来捕获特定的信号。
    • 使用 signal() 或者 sigaction() 函数可以设置信号的处理方式,包括忽略信号、执行默认操作或者调用自定义的信号处理函数。

实现举例

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

void signal_handler(int signal) {
    printf("Received signal %d, terminating...\n", signal);
    exit(0);
}

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

    // 创建子进程
    pid_t pid = fork();

    if (pid == -1) {
        perror("fork failed");
        exit(1);
    } else if (pid == 0) {
        // 子进程
        printf("Child process (PID %d) created\n", getpid());
        sleep(5); // 让子进程休眠5秒,以便我们可以发送信号给它
    } else {
        // 父进程
        printf("Parent process (PID %d) created\n", getpid());
        sleep(2); // 让父进程休眠2秒,以确保子进程已经创建并处于休眠状态

        // 发送 SIGTERM 信号给子进程
        printf("Sending SIGTERM signal to child process...\n");
        kill(pid, SIGTERM);
    }

    return 0;
}
实例说明

这个示例中,首先通过调用 signal() 函数注册了两个信号处理函数,用于处理 SIGINT 和 SIGTERM 信号。当进程收到这些信号时,它会调用相应的处理函数。在这个例子中,处理函数简单地打印一条消息并退出进程。接下来,我们调用 fork() 函数创建一个子进程。fork() 函数会返回两次,一次是在父进程中,一次是在子进程中。在父进程中,fork() 返回新创建的子进程的 PID;在子进程中,fork() 返回 0。通过检查 fork() 的返回值,我们可以确定是在父进程中还是子进程中执行。在子进程中,打印一条消息并休眠5秒钟,以便我们可以发送信号给它。在父进程中,打印一条消息并休眠2秒钟,以确保子进程已经创建并处于休眠状态。然后,使用 kill() 函数向子进程发送 SIGTERM 信号。kill() 函数的第一个参数是要发送信号的进程的 PID,第二个参数是要发送的信号的类型。在这个例子中,发送 SIGTERM 信号给子进程。当子进程收到 SIGTERM 信号时,它会调用我们之前注册的信号处理函数,打印一条消息并退出进程。

总结

  1. 权限和限制

    • 通常情况下,只有进程的所有者或者超级用户才能向其他进程发送信号。
    • 有些信号,如SIGKILL和SIGSTOP,不能被进程捕获或忽略。
  2. 信号的缺点

    • 信号不能携带复杂的数据,只能传递简单的信号编号。
    • 由于信号的异步性质,可能会引发竞态条件或其他并发问题。
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

匠心码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值