无名管道、有名管道、信号、信号处理

发布于:2025-02-25 ⋅ 阅读:(8) ⋅ 点赞:(0)

1. 进程间通信(IPC)

进程间通信(IPC)是指在不同进程之间交换数据或信息的机制。常见的 IPC 方法包括:

1.1 管道(Pipe)
  • 无名管道(Anonymous Pipe)

    • 只能用于具有亲缘关系的进程间通信(如父子进程)。

    • 使用 pipe() 系统调用创建。

    • 特点:

      • 读操作:如果管道中有数据,则直接读取;如果没有数据,会阻塞等待。

      • 写操作:如果管道中有读端且未满,则直接写入;如果管道已满,会阻塞等待。

      • 如果管道中没有读端,写入数据会导致管道破裂(SIGPIPE 信号)。

  • 有名管道(Named Pipe/FIFO)

    • 可以用于任意两个进程之间的通信。

    • 使用 mkfifo() 系统调用创建。

    • 特点:

      • 必须读写两端同时打开,才能继续执行;否则会阻塞等待。

1.2 信号(Signal)
  • 定义

    • 提供一种内核层与用户层之间的通知机制。

    • 信号是一种软件中断,用于通知进程某些事件的发生。

  • 信号类型

    • SIGINT(2):中断信号(如 Ctrl+C)。

    • SIGQUIT(3):退出信号(如 Ctrl+\)。

    • SIGSEGV(11):段错误。

    • SIGPIPE(13):管道破裂。

    • SIGALRM(14):定时信号。

    • SIGCHLD(17):子进程结束。

    • SIGSTOP(19):停止进程。

    • SIGTSTP(20):挂起进程(如 Ctrl+Z)。

    • SIGIO(29):异步 I/O 信号。

  • 对信号的处理方式

    1. 忽略:信号来了,不处理该信号。

    2. 缺省:信号来了,按照默认的方式处理信号。

    3. 捕捉:信号来了,按照指定的方式处理信号。

    • 注意:SIGKILL(9)和 SIGSTOP(19)不能被忽略或捕捉。

  • 函数接口

    typedef void (*sighandler_t)(int);
    sighandler_t signal(int signum, sighandler_t handler);
    • 功能:修改信号的处理方式。

    • 参数:

      • signum:信号编号。

      • handler:信号处理方式(SIG_IGN 忽略,SIG_DFL 缺省)。

    • 返回值:

      • 成功返回之前的信号处理函数。

      • 失败返回 SIG_ERR

1.3 消息队列(Message Queue)
  • 提供一种在进程间传递消息的机制。

  • 消息队列允许一个或多个进程向队列中写入消息,同时允许一个或多个进程读取这些消息。

1.4 共享内存(Shared Memory)
  • 允许多个进程共享同一块内存区域。

  • 提供高效的进程间通信,但需要同步机制(如互斥锁)来避免数据竞争。

1.5 信号量(Semaphore)
  • 提供一种同步机制,用于控制对共享资源的访问。

  • 函数接口:

    int sem_init(sem_t *sem, int pshared, unsigned int value);
    int sem_destroy(sem_t *sem);
    int sem_wait(sem_t *sem);
    int sem_post(sem_t *sem);
    • sem_init:初始化信号量。

    • sem_destroy:销毁信号量。

    • sem_wait:申请信号量资源(资源数 - 1)。

    • sem_post:释放信号量资源(资源数 + 1)。

1.6 套接字(Socket)
  • 提供一种在不同主机上的进程之间进行通信的机制。

  • 支持多种协议(如 TCP/IP、UDP/IP)。


2. 管道的详细说明

2.1 无名管道
  • 创建

    int pipe(int pipefd[2]);
    • 功能:创建操作管道的两个文件描述符。

    • 参数:

      • pipefd[0]:读文件描述符。

      • pipefd[1]:写文件描述符。

    • 返回值:

      • 成功返回 0。

      • 失败返回 -1。

2.2 有名管道
  • 创建

    int mkfifo(const char *pathname, mode_t mode);
    • 功能:创建管道文件。

    • 参数:

      • pathname:管道文件名。

      • mode:权限。

    • 返回值:

      • 成功返回 0。

      • 失败返回 -1。


3. 信号的详细说明

3.1 信号处理
  • 信号列表

    • 使用 kill -l 命令查看所有信号。

    • 示例:

      1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
      6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
      11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
  • 信号处理方式

    • 忽略SIG_IGN

    • 缺省SIG_DFL

    • 捕捉:自定义处理函数。

  • 示例代码

    #include <stdio.h>
    #include <signal.h>
    
    void handle_sigint(int sig) {
        printf("SIGINT signal received\n");
    }
    
    void handle_sigquit(int sig) {
        printf("SIGQUIT signal received\n");
    }
    
    int main() {
        signal(SIGINT, handle_sigint);  // 捕捉 SIGINT
        signal(SIGQUIT, handle_sigquit);  // 捕捉 SIGQUIT
    
        printf("Press Ctrl+C or Ctrl+\\ to test signals\n");
        while (1) {
            // 等待信号
        }
    
        return 0;
    }
3.2 定时信号
  • alarm()

    unsigned int alarm(unsigned int seconds);
    • 功能:定时 seconds 秒后给当前进程发送 SIGALRM 信号。

    • 参数:

      • seconds:秒数。

    • 返回值:

      • 成功返回之前定时剩余的秒数。

      • 如果之前没有定时返回 0。

3.3 发送信号
  • kill()

    int kill(pid_t pid, int sig);
    • 功能:向 pid 对应的进程发送 sig 信号。

    • 参数:

      • pid:目标进程的 PID。

      • sig:信号编号。

    • 返回值:

      • 成功返回 0。

      • 失败返回 -1。


4. 总结

  • 管道

    • 无名管道:用于具有亲缘关系的进程间通信。

    • 有名管道:用于任意两个进程之间的通信。

  • 信号

    • 提供内核层与用户层之间的通知机制。

    • 可以通过 signal() 设置信号处理方式。

  • 消息队列

    • 提供进程间传递消息的机制。

  • 共享内存

    • 提供高效的进程间通信,但需要同步机制。

  • 信号量

    • 提供同步机制,用于控制对共享资源的访问。

  • 套接字

    • 提供不同主机上的进程之间进行通信的机制