温馨提示×

Linux进程通信机制:管道、消息队列和共享内存

小樊
63
2025-06-16 19:10:53
栏目: 智能运维

Linux进程通信(IPC)机制允许进程之间交换数据和信息。以下是三种常见的Linux IPC机制:

1. 管道(Pipes)

定义: 管道是一种半双工的通信方式,数据只能单向流动,通常用于具有亲缘关系的进程之间(例如父子进程)。

类型

  • 无名管道(Unnamed Pipes):只能在具有共同祖先的两个进程之间使用。
  • 命名管道(Named Pipes,FIFO):可以在不相关的进程之间使用,因为它们在文件系统中有一个名称。

特点

  • 管道是先进先出(FIFO)的数据结构。
  • 数据传输是字节流,没有消息边界。
  • 管道是阻塞的,发送方在管道满时会阻塞,接收方在管道空时会阻塞。

示例代码

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

int main() {
    int pipefd[2];
    pid_t pid;
    char buffer[256];

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // 子进程
        close(pipefd[1]); // 关闭写端
        read(pipefd[0], buffer, sizeof(buffer));
        printf("Child received: %s\n", buffer);
        close(pipefd[0]);
    } else { // 父进程
        close(pipefd[0]); // 关闭读端
        write(pipefd[1], "Hello from parent", 20);
        close(pipefd[1]);
    }

    return 0;
}

2. 消息队列(Message Queues)

定义: 消息队列是一种进程间通信机制,允许进程发送和接收消息。消息队列中的消息有类型,可以根据类型进行选择性接收。

特点

  • 消息队列是消息的链表,存放在内核中并由消息队列标识符标识。
  • 每条消息都有一个类型,接收者可以选择性地接收特定类型的消息。
  • 消息队列是异步的,发送和接收操作不会相互阻塞。

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct msg_buffer {
    long msg_type;
    char msg_text[100];
};

int main() {
    int msgid;
    key_t key = 1234;
    struct msg_buffer message;

    // 创建消息队列
    msgid = msgget(key, IPC_CREAT | 0666);
    if (msgid == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    // 发送消息
    message.msg_type = 1;
    strcpy(message.msg_text, "Hello from sender");
    if (msgsnd(msgid, &message, sizeof(message.msg_text), 0) == -1) {
        perror("msgsnd");
        exit(EXIT_FAILURE);
    }

    // 接收消息
    if (msgrcv(msgid, &message, sizeof(message.msg_text), 1, 0) == -1) {
        perror("msgrcv");
        exit(EXIT_FAILURE);
    }
    printf("Received message: %s\n", message.msg_text);

    // 删除消息队列
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        exit(EXIT_FAILURE);
    }

    return 0;
}

3. 共享内存(Shared Memory)

定义: 共享内存是最快的IPC机制之一,它允许多个进程访问同一块物理内存。进程可以将这块内存映射到自己的地址空间,从而实现数据共享。

特点

  • 共享内存是最高效的IPC机制,因为避免了数据的复制。
  • 需要使用同步机制(如信号量)来避免竞态条件。
  • 共享内存段在所有引用它的进程终止后仍然存在,直到被显式删除。

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

int main() {
    int shmid;
    key_t key = 1234;
    char *shmaddr;
    pid_t pid;

    // 创建共享内存段
    shmid = shmget(key, 1024, IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }

    // 将共享内存段附加到进程地址空间
    shmaddr = shmat(shmid, NULL, 0);
    if (shmaddr == (char *) -1) {
        perror("shmat");
        exit(EXIT_FAILURE);
    }

    // 写入数据
    strcpy(shmaddr, "Hello from shared memory");

    pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // 子进程
        sleep(2); // 等待父进程写入数据
        printf("Child read: %s\n", shmaddr);
        shmdt(shmaddr); // 分离共享内存段
    } else { // 父进程
        sleep(1); // 等待子进程读取数据
        printf("Parent read: %s\n", shmaddr);
        shmdt(shmaddr); // 分离共享内存段
    }

    // 删除共享内存段
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl");
        exit(EXIT_FAILURE);
    }

    return 0;
}

总结

  • 管道:适用于具有亲缘关系的进程之间的单向通信。
  • 消息队列:适用于需要消息类型选择和异步通信的场景。
  • 共享内存:适用于需要高效数据共享的场景,但需要额外的同步机制来避免竞态条件。

选择合适的IPC机制取决于具体的应用需求和性能考虑。

0