共享内存是Linux进程间通信(IPC)的一种重要机制,它允许多个进程直接访问同一块内存区域,从而实现高效的数据传输。由于共享内存不需要复制数据,因此其通信速度远快于管道、消息队列等其他IPC机制。接下来将详细介绍共享内存的使用方法,并给出示例代码。
共享内存的基本概念
共享内存是由操作系统提供的一块内存区域,多个进程可以映射(attach)到自己的地址空间中。这种方式使得各个进程可以共享数据,无需进行数据复制。在使用共享内存时,通常的步骤包括:
- 创建共享内存段
- 将共享内存映射到进程的地址空间
- 在共享内存中读写数据
- 解除映射
- 删除共享内存段
代码示例
下面是一个简单的示例,演示了如何使用共享内存进行进程间通信。我们将使用POSIX共享内存函数。
生产者-消费者模型
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#define SHM_SIZE 1024 // 共享内存大小
#define SHM_NAME "/my_shm"
#define SEM_NAME "/my_sem"
// 生产者进程
void producer() {
int shm_fd;
char *ptr;
sem_t *sem;
// 创建共享内存
shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, SHM_SIZE);
ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
// 创建信号量
sem = sem_open(SEM_NAME, O_CREAT, 0666, 1);
for (int i = 0; i < 10; i++) {
// 写入数据
sem_wait(sem); // P操作
sprintf(ptr, "Message %d", i);
printf("Produced: %s\n", ptr);
sem_post(sem); // V操作
sleep(1);
}
// 清理
munmap(ptr, SHM_SIZE);
shm_unlink(SHM_NAME);
sem_close(sem);
sem_unlink(SEM_NAME);
}
// 消费者进程
void consumer() {
int shm_fd;
char *ptr;
sem_t *sem;
// 打开共享内存
shm_fd = shm_open(SHM_NAME, O_RDONLY, 0666);
ptr = mmap(0, SHM_SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
// 打开信号量
sem = sem_open(SEM_NAME, 0);
for (int i = 0; i < 10; i++) {
sem_wait(sem); // P操作
printf("Consumed: %s\n", ptr);
sem_post(sem); // V操作
sleep(1);
}
// 清理
munmap(ptr, SHM_SIZE);
close(shm_fd);
sem_close(sem);
}
int main() {
if (fork() == 0) {
consumer(); // 子进程执行消费者
} else {
producer(); // 父进程执行生产者
wait(NULL); // 等待子进程结束
}
return 0;
}
代码说明
- 创建和打开共享内存:生产者使用
shm_open
函数创建共享内存,指定其名称和大小。消费者通过同样的函数打开共享内存。 - 映射共享内存:使用
mmap
将共享内存映射到进程的地址空间。 - 信号量的使用:为了避免竞争条件,采用POSIX信号量来控制对共享内存的访问。这样确保同一时刻只有一个进程可以读写数据。
- 数据生产和消费:生产者将数据写入共享内存,消费者则从中读取数据。
结论
共享内存是一种高效的进程间通信机制,在需要快速数据交换的场景中特别有用。尽管其使用相对简单,但需注意数据一致性和进程同步问题。通过合适的同步机制,例如信号量,可以有效避免多个进程对共享内存的同时访问带来的问题。在实际应用中,共享内存常与其他IPC机制结合使用,以实现更复杂的通信需求。