进程间通信方式有哪些?各举例实现一个demo

进程间通信(Inter-Process Communication,IPC)是指不同进程之间进行数据交换的方式,它允许不同的进程相互合作,完成共同的任务。常见的进程间通信方式有以下几种:

  1. 管道(Pipe)

管道是一种半双工的通信方式,只能在具有亲缘关系的进程之间使用,一般用于父子进程之间的通信。

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

int main()
{
    int fd[2];
    pid_t pid;
    char buf[1024];
    if (pipe(fd) < 0) {
        perror("pipe error");
        exit(1);
    }
    if ((pid = fork()) < 0) {
        perror("fork error");
        exit(1);
    } else if (pid > 0) { // 父进程
        close(fd[0]); // 关闭读端
        write(fd[1], 'hello world\n', 12);
    } else { // 子进程
        close(fd[1]); // 关闭写端
        read(fd[0], buf, 1024);
        printf('%s', buf);
    }
    return 0;
}
  1. 命名管道(Named Pipe)

命名管道是一种半双工的通信方式,可以在不具有亲缘关系的进程之间使用,一般用于客户端与服务器之间的通信。

// 服务端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd;
    char buf[1024];
    if (mkfifo('fifo', 0666) < 0) { // 创建命名管道
        perror("mkfifo error");
        exit(1);
    }
    if ((fd = open('fifo', O_RDONLY)) < 0) { // 打开命名管道
        perror("open error");
        exit(1);
    }
    read(fd, buf, 1024);
    printf('%s', buf);
    close(fd);
    return 0;
}

// 客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd;
    if ((fd = open('fifo', O_WRONLY)) < 0) { // 打开命名管道
        perror("open error");
        exit(1);
    }
    write(fd, 'hello world\n', 12);
    close(fd);
    return 0;
}
  1. 消息队列(Message Queue)

消息队列是一种异步的通信方式,可以在不具有亲缘关系的进程之间使用。

// 发送方
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>

struct msgbuf {
    long mtype;
    char mtext[1024];
};

int main()
{
    int msqid;
    struct msgbuf buf;
    key_t key;
    if ((key = ftok('.', 'a')) < 0) { // 创建key
        perror("ftok error");
        exit(1);
    }
    if ((msqid = msgget(key, IPC_CREAT | 0666)) < 0) { // 创建消息队列
        perror("msgget error");
        exit(1);
    }
    buf.mtype = 1; // 消息类型
    strcpy(buf.mtext, 'hello world');
    if (msgsnd(msqid, &buf, strlen(buf.mtext), 0) < 0) { // 发送消息
        perror("msgsnd error");
        exit(1);
    }
    return 0;
}

// 接收方
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>

struct msgbuf {
    long mtype;
    char mtext[1024];
};

int main()
{
    int msqid;
    struct msgbuf buf;
    key_t key;
    if ((key = ftok('.', 'a')) < 0) { // 创建key
        perror("ftok error");
        exit(1);
    }
    if ((msqid = msgget(key, IPC_CREAT | 0666)) < 0) { // 创建消息队列
        perror("msgget error");
        exit(1);
    }
    if (msgrcv(msqid, &buf, 1024, 1, 0) < 0) { // 接收消息
        perror("msgrcv error");
        exit(1);
    }
    printf('%s', buf.mtext);
    if (msgctl(msqid, IPC_RMID, NULL) < 0) { // 删除消息队列
        perror("msgctl error");
        exit(1);
    }
    return 0;
}
  1. 共享内存(Shared Memory)

共享内存是一种高效的通信方式,可以实现多个进程之间的数据共享。

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

struct shared_mem {
    int flag;
    char buf[1024];
};

int main()
{
    int shmid;
    struct shared_mem *shmptr;
    key_t key;
    if ((key = ftok('.', 'a')) < 0) { // 创建key
        perror("ftok error");
        exit(1);
    }
    if ((shmid = shmget(key, sizeof(struct shared_mem), IPC_CREAT | 0666)) < 0) { // 创建共享内存
        perror("shmget error");
        exit(1);
    }
    if ((shmptr = (struct shared_mem *)shmat(shmid, NULL, 0)) == (void *)-1) { // 将共享内存映射到进程的地址空间中
        perror("shmat error");
        exit(1);
    }
    while (1) {
        if (shmptr->flag == 0) {
            fgets(shmptr->buf, sizeof(shmptr->buf), stdin);
            shmptr->flag = 1;
        }
    }
    if (shmdt(shmptr) < 0) { // 解除共享内存映射
        perror("shmdt error");
        exit(1);
    }
    return 0;
}

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

struct shared_mem {
    int flag;
    char buf[1024];
};

int main()
{
    int shmid;
    struct shared_mem *shmptr;
    key_t key;
    if ((key = ftok('.', 'a')) < 0) { // 创建key
        perror("ftok error");
        exit(1);
    }
    if ((shmid = shmget(key, sizeof(struct shared_mem), IPC_CREAT | 0666)) < 0) { // 创建共享内存
        perror("shmget error");
        exit(1);
    }
    if ((shmptr = (struct shared_mem *)shmat(shmid, NULL, 0)) == (void *)-1) { // 将共享内存映射到进程的地址空间中
        perror("shmat error");
        exit(1);
    }
    while (1) {
        if (shmptr->flag == 1) {
            printf('%s', shmptr->buf);
            shmptr->flag = 0;
        }
    }
    if (shmdt(shmptr) < 0) { // 解除共享内存映射
        perror("shmdt error");
        exit(1);
    }
    return 0;
}
  1. 信号量(Semaphore)

信号量是一种用于进程间同步和互斥的机制。

// 写进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>

int main()
{
    int semid;
    struct sembuf semops;
    key_t key;
    if ((key = ftok('.', 'a')) < 0) { // 创建key
        perror("ftok error");
        exit(1);
    }
    if ((semid = semget(key, 1, IPC_CREAT | 0666)) < 0) { // 创建信号量
        perror("semget error");
        exit(1);
    }
    semops.sem_num = 0;
    semops.sem_op = 1; // 信号量加1
    semops.sem_flg = SEM_UNDO;
    while (1) {
        semop(semid, &semops, 1); // 发送信号量
        sleep(1);
    }
    return 0;
}

// 读进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>

int main()
{
    int semid;
    struct sembuf semops;
    key_t key;
    if ((key = ftok('.', 'a')) < 0) { // 创建key
        perror("ftok error");
        exit(1);
    }
    if ((semid = semget(key, 1, IPC_CREAT | 0666)) < 0) { // 创建信号量
        perror("semget error");
        exit(1);
    }
    semops.sem_num = 0;
    semops.sem_op = -1; // 信号量减1
    semops.sem_flg = SEM_UNDO;
    while (1) {
        semop(semid, &semops, 1); // 接收信号量
        printf('hello world\n');
    }
    return 0;
}

除了以上几种常见的进程间通信方式,还有其他一些方法,例如:

  • 套接字(Socket):套接字是网络编程中的一个概念,它可以用于进程间通信,即使是在不同主机上的进程之间。
  • 信号(Signal):信号是一种异步的通信方式,可以用于进程间通信,但只能传递简单的信号,不能传递数据。
  • 共享文件(Shared File):共享文件可以用于进程间通信,但效率比较低。

选择哪种进程间通信方式取决于具体的应用场景。例如,如果需要在父子进程之间进行简单的通信,可以选择管道;如果需要在不具有亲缘关系的进程之间进行数据交换,可以选择消息队列或共享内存;如果需要进行进程同步或互斥,可以选择信号量。

总结

进程间通信是多进程编程中不可缺少的一部分,它允许不同的进程相互合作,完成共同的任务。选择合适的进程间通信方式可以提高程序的性能和效率。

进程间通信方式详解:管道、命名管道、消息队列、共享内存、信号量

原文地址: https://www.cveoy.top/t/topic/mR4e 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录