• Linux 进程间通信(IPC)详解:匿名管道、命名管道与共享内存


    目录

    前言

    一. 匿名管道(Pipes)

    1.1 原理

    1.2 使用场景

    1.3 实现

    二. 命名管道(FIFO)

    2.1 原理

    2.2 使用场景

    2.3 实现

    三. 共享内存

    3.1 原理

    3.2 使用场景

    3.3 实现

    四.结论


    前言

    在现代操作系统中,进程间通信(IPC)是实现多任务协作的关键技术。Linux系统提供了多种IPC机制,其中匿名管道、命名管道和共享内存是最为常用的三种方式。本文将详细解析这三种IPC机制的原理、使用场景以及如何在C语言中实现它们。

    一. 匿名管道(Pipes)

    1.1 原理

    匿名管道是一种半双工的通信方式,允许具有亲缘关系的进程(如父子进程)进行通信。它由两个端点组成:一个读端和一个写端。数据只能单向流动,即数据只能从写端流向读端。

    1.2 使用场景

    • 父子进程间的数据传递
    • 兄弟进程间的数据传递(通过fork)

    1.3 实现

    在C语言中,可以使用pipe()系统调用来创建匿名管道。以下是一个简单的示例:

    1. #include
    2. #include
    3. #include
    4. int main() {
    5. int pipefd[2];
    6. char message[] = "Hello, child!";
    7. char buffer[256];
    8. // 创建管道
    9. if (pipe(pipefd) == -1) {
    10. perror("pipe");
    11. return 1;
    12. }
    13. pid_t pid = fork();
    14. if (pid == -1) {
    15. perror("fork");
    16. return 1;
    17. }
    18. if (pid == 0) {
    19. // 子进程
    20. close(pipefd[1]); // 关闭写端
    21. read(pipefd[0], buffer, sizeof(buffer));
    22. printf("Child received: %s\n", buffer);
    23. } else {
    24. // 父进程
    25. close(pipefd[0]); // 关闭读端
    26. write(pipefd[1], message, strlen(message));
    27. close(pipefd[1]); // 关闭写端
    28. wait(NULL); // 等待子进程结束
    29. }
    30. return 0;
    31. }

    二. 命名管道(FIFO)

    2.1 原理

    命名管道(也称为FIFO)是一种全双工的通信方式,它在文件系统中以文件的形式存在。与匿名管道不同,命名管道允许任意两个进程进行通信,无论它们是否具有亲缘关系。

    2.2 使用场景

    • 任意两个进程间的数据传递
    • 作为客户端-服务器模型中的通信媒介

    2.3 实现

    在C语言中,可以使用mkfifo()系统调用来创建命名管道。以下是一个创建和使用命名管道的示例:

    1. #include
    2. #include
    3. #include
    4. int main() {
    5. int fd;
    6. char buffer[256];
    7. // 创建命名管道
    8. if (mkfifo("my_fifo", 0666) == -1) {
    9. perror("mkfifo");
    10. return 1;
    11. }
    12. // 打开命名管道进行写操作
    13. fd = open("my_fifo", O_WRONLY);
    14. if (fd == -1) {
    15. perror("open");
    16. return 1;
    17. }
    18. write(fd, "Hello, FIFO!", strlen("Hello, FIFO!"));
    19. close(fd);
    20. // 打开命名管道进行读操作
    21. fd = open("my_fifo", O_RDONLY);
    22. if (fd == -1) {
    23. perror("open");
    24. return 1;
    25. }
    26. read(fd, buffer, sizeof(buffer));
    27. printf("Received: %s\n", buffer);
    28. close(fd);
    29. return 0;
    30. }

    三. 共享内存

    3.1 原理

    共享内存允许两个或多个进程访问同一块物理内存区域。这种方式提供了最快的IPC速度,因为它避免了数据在用户空间和内核空间之间的复制。

    3.2 使用场景

    • 需要快速交换大量数据的进程
    • 实时系统或高性能计算

    3.3 实现

    在C语言中,可以使用shmget()shmat()shmdt()系统调用来创建、连接和断开共享内存。以下是一个简单的共享内存示例:

    1. #include
    2. #include
    3. #include
    4. #include
    5. int main() {
    6. int shmid;
    7. char *shm, *str = "Hello, shared memory!";
    8. struct shmid_ds shmseg;
    9. // 创建共享内存段
    10. shmid = shmget(IPC_PRIVATE, strlen(str) + 1, IPC_CREAT | 0666);
    11. if (shmid == -1) {
    12. perror("shmget");
    13. return 1;
    14. }
    15. // 连接共享内存段
    16. shm = shmat(shmid, NULL, 0);
    17. if (shm == (char *) -1) {
    18. perror("shmat");
    19. return 1;
    20. }
    21. // 将字符串复制到共享内存
    22. strcpy(shm, str);
    23. // 断开共享内存段
    24. if (shmdt(shm) == -1) {
    25. perror("shmdt");
    26. return 1;
    27. }
    28. // 删除共享内存段
    29. if (shmctl(shmid, IPC_RMID, &shmseg) == -1) {
    30. perror("shmctl");
    31. return 1;
    32. }
    33. printf("Shared memory created and message sent.\n");
    34. return 0;
    35. }

    在实际应用中,共享内存通常需要配合信号量或互斥锁来实现进程间的同步

    四.结论

    匿名管道、命名管道和共享内存各有优势和适用场景。

    在选择IPC机制时,应根据实际需求考虑数据传输的速度、大小、方向以及进程间的亲缘关系等因素。

    通过合理利用这些IPC机制,可以有效地实现进程间的协作和数据共享。

  • 相关阅读:
    R语言如何写一个爬虫代码模版
    Windows10 任务栏卡死
    搭建nacos集群 和 网关
    vsftp3.0 匿名用户,本地用户,虚拟用户,主动模式以及被动模式,docker vsftpd,k8s vsftpd
    Rocketmq学习1——Rocketmq架构&消息存储&刷盘机制
    支持AGP8的Android路由库URouter
    MySQL架构 & InnoDB存储引擎
    使用迁移学习在线校准深度学习模型
    工作中遇到的问题与解决办法(三)
    08-类加载的时机
  • 原文地址:https://blog.csdn.net/weixin_55582891/article/details/136487405