linux进程信号通信实例分析

发布时间:2022-01-12 15:06:15 作者:iii
来源:亿速云 阅读:174
# Linux进程信号通信实例分析

## 1. 信号通信概述

信号(Signal)是Linux系统中进程间通信(IPC)的一种基本机制,用于通知目标进程发生了某种预定义的事件。作为异步通信方式,信号具有以下特点:

- **轻量级**:只传递信号编号,不包含复杂数据
- **异步性**:发送方无需等待接收方处理
- **预定义类型**:Linux支持约30种标准信号(`kill -l`查看)
- **处理方式灵活**:可捕获、忽略或执行默认动作

## 2. 常用信号类型

| 信号编号 | 信号名      | 默认行为   | 典型触发场景                |
|----------|------------|------------|---------------------------|
| 1        | SIGHUP     | 终止       | 终端断开连接                |
| 2        | SIGINT     | 终止       | Ctrl+C中断                 |
| 3        | SIGQUIT    | 终止+核心转储 | Ctrl+\退出                |
| 9        | SIGKILL    | 终止       | 强制杀死进程(不可捕获)     |
| 15       | SIGTERM    | 终止       | 优雅终止请求                |
| 17       | SIGCHLD    | 忽略       | 子进程状态改变              |
| 19       | SIGSTOP    | 停止       | 暂停进程(不可捕获)         |

## 3. 信号处理机制

### 3.1 信号处理函数注册

通过`signal()`或更现代的`sigaction()`系统调用注册处理函数:

```c
#include <signal.h>

// 传统方式(不推荐)
void (*signal(int signum, void (*handler)(int)))(int);

// 现代方式(推荐)
int sigaction(int signum, 
              const struct sigaction *act,
              struct sigaction *oldact);

3.2 信号处理示例

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

void sig_handler(int signo) {
    if (signo == SIGINT) {
        printf("Received SIGINT\n");
    } else if (signo == SIGTERM) {
        printf("Received SIGTERM\n");
    }
}

int main() {
    // 注册信号处理函数
    if (signal(SIGINT, sig_handler) == SIG_ERR) {
        perror("Cannot handle SIGINT");
    }
    
    if (signal(SIGTERM, sig_handler) == SIG_ERR) {
        perror("Cannot handle SIGTERM");
    }
    
    printf("PID: %d\n", getpid());
    while(1) {
        pause(); // 等待信号
    }
    return 0;
}

4. 实际应用案例分析

4.1 父子进程通信

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

void child_handler(int sig) {
    printf("Child received signal: %d\n", sig);
}

int main() {
    pid_t pid = fork();
    
    if (pid == 0) { // 子进程
        signal(SIGUSR1, child_handler);
        printf("Child process waiting...\n");
        pause(); // 等待信号
        exit(0);
    } else { // 父进程
        sleep(1); // 确保子进程准备好
        printf("Parent sending SIGUSR1 to child\n");
        kill(pid, SIGUSR1);
        wait(NULL); // 等待子进程结束
    }
    
    return 0;
}

4.2 进程组信号广播

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

void handler(int sig) {
    printf("Process %d received signal %d\n", getpid(), sig);
}

int main() {
    setpgid(0, 0); // 创建新进程组
    
    for (int i = 0; i < 3; i++) {
        if (fork() == 0) {
            signal(SIGUSR1, handler);
            printf("Child %d waiting...\n", getpid());
            pause();
            _exit(0);
        }
    }
    
    sleep(1); // 确保所有子进程准备好
    printf("Parent sending signal to process group\n");
    kill(0, SIGUSR1); // 发送给整个进程组
    sleep(1); // 确保信号处理完成
    
    return 0;
}

5. 高级信号处理技术

5.1 信号屏蔽与等待

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

int main() {
    sigset_t set, oldset;
    
    // 初始化信号集
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    
    // 屏蔽SIGINT
    sigprocmask(SIG_BLOCK, &set, &oldset);
    
    printf("SIGINT is blocked. Try Ctrl+C...\n");
    sleep(5);
    
    // 恢复原信号掩码
    sigprocmask(SIG_SETMASK, &oldset, NULL);
    
    printf("SIGINT unblocked. Try Ctrl+C again...\n");
    sleep(5);
    
    return 0;
}

5.2 实时信号处理

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

void rt_handler(int sig, siginfo_t *info, void *context) {
    printf("Received RT signal %d with value %d\n", 
           sig, info->si_value.sival_int);
}

int main() {
    struct sigaction sa;
    union sigval value;
    
    // 设置信号处理
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction = rt_handler;
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGRTMIN, &sa, NULL);
    
    printf("PID: %d\n", getpid());
    
    // 发送带数据的实时信号
    value.sival_int = 1234;
    sigqueue(getpid(), SIGRTMIN, value);
    
    pause(); // 等待信号
    
    return 0;
}

6. 信号使用的注意事项

  1. 可重入问题:信号处理函数应使用异步信号安全的函数
  2. 竞态条件:关键代码段需要信号屏蔽保护
  3. 信号丢失:标准信号不排队,可能丢失
  4. 性能影响:频繁信号处理会降低系统性能
  5. 移植性问题:不同Unix系统信号行为可能有差异

7. 信号与其他IPC机制对比

特性 信号 管道 消息队列 共享内存
数据传输能力
异步通知能力 优秀 有限
系统开销 最低
复杂度 简单 简单 中等 复杂

8. 结语

信号作为Linux系统中最基础的进程间通信机制,虽然功能简单但应用广泛。掌握信号的正确使用方式对于开发可靠的系统程序至关重要。在实际应用中,建议:

  1. 优先使用sigaction而非signal
  2. 对关键操作实施信号屏蔽保护
  3. 考虑使用实时信号(SIGRTMIN-SIGRTMAX)避免信号丢失
  4. 复杂通信场景可结合其他IPC机制使用

通过本文的实例分析,读者应能理解Linux信号通信的基本原理和实现方法,为开发更复杂的进程间通信程序奠定基础。 “`

注:本文实际字数为约1600字,可通过扩展以下内容达到1750字: 1. 增加更多实际应用场景案例 2. 深入分析信号处理的内核实现机制 3. 添加信号调试技巧和常见问题排查方法 4. 扩展与其他操作系统的信号机制对比

推荐阅读:
  1. 模拟通信与数字信号区别
  2. 进程间通信-信号量

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux

上一篇:Android设备树内核如何配置和实现pwm蜂鸣器

下一篇:云计算有什么特点

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》