085. 使用C语言实现简单的进程间通信

在C语言中,进程间通信(IPC)是多个进程之间交换数据的一种方式。Linux系统提供了多种IPC机制,包括管道(Pipes)、消息队列(Message Queues)、共享内存(Shared Memory)和信号(Signals)。以下将分别实现这些简单的IPC机制。

1. 管道(Pipes)

管道是一种简单的IPC机制,用于在父子进程之间单向通信。匿名管道只能用于具有亲缘关系的进程之间,而命名管道(FIFO)可以用于不相关的进程之间。

示例代码:匿名管道

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

int main() {
    int pipefds[2];
    pid_t pid;

    // 创建管道
    if (pipe(pipefds) == -1) {
        perror("pipe");
        exit(1);
    }

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

    if (pid == 0) { // 子进程
        close(pipefds[1]); // 关闭写端
        char buffer[80];
        read(pipefds[0], buffer, sizeof(buffer)); // 从管道读取数据
        printf("子进程收到的消息:%s\n", buffer);
        close(pipefds[0]); // 关闭读端
    } else { // 父进程
        close(pipefds[0]); // 关闭读端
        char message[] = "Hello, World!";
        write(pipefds[1], message, sizeof(message)); // 向管道写入数据
        close(pipefds[1]); // 关闭写端
        wait(NULL); // 等待子进程结束
    }

    return 0;
}

示例运行

输入:

无输入

输出:

子进程收到的消息:Hello, World!

2. 消息队列(Message Queues)

消息队列是一种更高级的IPC机制,允许不相关的进程之间交换消息。消息队列可以存储多个消息,每个消息都有一个类型和数据。

示例代码:消息队列

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

// 消息结构
struct message {
    long mtype;
    char mtext[80];
};

int main() {
    key_t key;
    int msgid;
    struct message msg;

    // 创建消息队列
    key = ftok("queuefile", 65);
    msgid = msgget(key, 0666 | IPC_CREAT);

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

    if (pid == 0) { // 子进程
        msg.mtype = 1;
        msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0);
        printf("子进程收到的消息:%s\n", msg.mtext);
        msgctl(msgid, IPC_RMID, NULL); // 删除消息队列
    } else { // 父进程
        msg.mtype = 1;
        strcpy(msg.mtext, "Hello, World!");
        msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
        wait(NULL); // 等待子进程结束
    }

    return 0;
}

示例运行

输入:

无输入

输出:

子进程收到的消息:Hello, World!

3. 共享内存(Shared Memory)

共享内存允许多个进程共享同一块内存区域,从而实现高效的数据交换。

示例代码:共享内存

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

int main() {
    key_t key;
    int shmid;
    char* data;

    // 创建共享内存
    key = ftok("shmfile", 65);
    shmid = shmget(key, 1024, 0666 | IPC_CREAT);

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

    if (pid == 0) { // 子进程
        data = shmat(shmid, (void*)0, 0);
        printf("子进程收到的消息:%s\n", data);
        shmdt(data); // 分离共享内存
        shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
    } else { // 父进程
        data = shmat(shmid, (void*)0, 0);
        strcpy(data, "Hello, World!");
        wait(NULL); // 等待子进程结束
    }

    return 0;
}

示例运行

输入:

无输入

输出:

子进程收到的消息:Hello, World!

4. 信号(Signals)

信号是一种软件中断,用于在进程之间传递异步事件。信号可以用于简单的进程间通信,但通常用于错误处理和中断处理。

示例代码:信号

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

void signal_handler(int sig) {
    printf("收到信号:%d\n", sig);
}

int main() {
    signal(SIGINT, signal_handler); // 设置信号处理函数

    printf("按Ctrl+C发送SIGINT信号...\n");
    while (1) {
        sleep(1); // 休眠1秒
    }

    return 0;
}

示例运行

输入:

按Ctrl+C发送SIGINT信号...

输出:

收到信号:2

5. 总结

通过实现简单的进程间通信机制,可以理解不同IPC方法的特点和适用场景。管道适用于父子进程之间的单向通信,消息队列和共享内存适用于不相关进程之间的通信,而信号则用于简单的异步事件处理。在实际开发中,可以根据具体需求选择合适的IPC机制。

视频讲解

BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)