一、Linux 进程间通信
进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享内存、Socket(套接字)等。其中 Socket和支持不同主机上的两个进程IPC。
- 管道
#include <stdio.h> int pipe(int fd[2]); // 返回值:若成功返回0,失败返回-1;
- FIFO,也称为命名管道
#include <stdio.h> // 返回值:成功返回0, 出错返回-1 int mkfifo(const char* pathname, mode_t mode);
- 消息队列
#include <stdio.h> // 创建或打开消息队列:成功返回队列ID,失败返回-1 int msgget(key_t key, int flag); // 添加消息:成功返回0,失败返回-1 int msgsnd(int msqid, const void ptr, size_t size, int flag); // 读取消息:成功返回消息数据的长度,失败返回-1 int msgrcv(int msqid, void* ptr, size_t size, long type, int flag); // 控制消息队列:成功返回0, 失败返回-1 int msgctl(int msqid, int cmd, struct msqid_ds * buf);
- 信号量
#include <stdio.h> // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1 int semget(key_t key, int num_sems, int sem_flags); // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1 int semop(int semid, struct sembuf semoparray[], size_t numops); // 控制信号量的相关信息 int semctl(int semid, int sem_num, int cmd, ...);
- 共享内存
#include <stdio.h> // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1 int shmget(key_t key, size_t size, int flag); // 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1 void shmat(int shm_id, const void *addr, int flag); // 断开与共享内存的连接:成功返回0,失败返回-1 int shmdt(void addr); // 控制共享内存的相关信息:成功返回0,失败返回-1 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
二、Linux 进程间同步
常用的同步方式有:互斥锁、条件变量、读写锁、记录锁(文件锁)和信号灯,以下为互斥锁同步和条件变量同步示例。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #define SHM_SIZE 4096 #define SHM_NAME "/myshm" #define SEM_NAME "/mysem" typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; char buffer[SHM_SIZE]; } shm_t; int main(int argc, char *argv[]) { int fd, pid; shm_t *shm; pthread_mutexattr_t mutex_attr; pthread_condattr_t cond_attr; // 创建共享内存区域 fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd < 0) { perror("shm_open"); exit(1); } // 设置共享内存大小 if (ftruncate(fd, sizeof(shm_t)) < 0) { perror("ftruncate"); exit(1); } // 将共享内存映射到进程地址空间 shm = mmap(NULL, sizeof(shm_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (shm == MAP_FAILED) { perror("mmap"); exit(1); } // 初始化互斥量属性和条件变量属性 pthread_mutexattr_init(&mutex_attr); pthread_condattr_init(&cond_attr); pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); // 初始化互斥量和条件变量 pthread_mutex_init(&shm->mutex, &mutex_attr); pthread_cond_init(&shm->cond, &cond_attr); // 创建子进程 pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (pid == 0) { // 子进程写入共享内存 sleep(1); pthread_mutex_lock(&shm->mutex); sprintf(shm->buffer, "Hello, world!"); pthread_cond_signal(&shm->cond); pthread_mutex_unlock(&shm->mutex); exit(0); } else { // 父进程读取共享内存 pthread_mutex_lock(&shm->mutex); pthread_cond_wait(&shm->cond, &shm->mutex); printf("Received message: %s\n", shm->buffer); pthread_mutex_unlock(&shm->mutex); } // 删除共享内存 if (shm_unlink(SHM_NAME) < 0) { perror("shm_unlink"); exit(1); } return 0; }