共享内存是最快的进程间通信(IPC)方式,允许多个进程直接访问同一块物理内存。
#include <sys/shm.h>
#include <sys/ipc.h>
// 创建共享内存段
int shmget(key_t key, size_t size, int shmflg);
// key: 共享内存标识符(通常用ftok生成)
// size: 共享内存大小
// shmflg: 标志(IPC_CREAT|权限)
// 返回值:共享内存ID(shmid),失败返回-1
// 将共享内存映射到进程地址空间
void *shmat(int shmid, const void *shmaddr, int shmflg);
// shmid: 共享内存ID
// shmaddr: 映射地址(通常为NULL,由系统选择)
// shmflg: 标志(SHM_RDONLY只读)
// 返回值:映射后的地址,失败返回(void*)-1
// 分离共享内存
int shmdt(const void *shmaddr);
// 返回值:成功返回0,失败返回-1
// 控制共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
// cmd: IPC_STAT(获取状态), IPC_SET(设置状态), IPC_RMID(删除)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
key_t key = ftok("/tmp", 'a');
int shmid = shmget(key, 1024, IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget");
exit(1);
}
pid_t pid = fork();
if (pid == 0) {
// 子进程:写入数据
char *shm = shmat(shmid, NULL, 0);
if (shm == (void*)-1) {
perror("shmat");
exit(1);
}
strcpy(shm, "Hello from child process!");
shmdt(shm);
exit(0);
} else {
// 父进程:等待子进程写入后读取
wait(NULL);
char *shm = shmat(shmid, NULL, SHM_RDONLY);
if (shm == (void*)-1) {
perror("shmat");
exit(1);
}
printf("Parent received: %s\n", shm);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
}
return 0;
}
编译命令:
gcc -o shm_demo shm_demo.c
./shm_demo
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
// pathname: 存在的文件路径
// proj_id: 项目ID(低8位有效)
// 返回值:key_t,失败返回-1
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
// addr: 映射起始地址(通常NULL,系统自动选择)
// length: 映射长度
// prot: 保护标志
// flags: 映射标志
// fd: 文件描述符
// offset: 文件偏移量
// 返回值:映射后的地址,失败返回MAP_FAILED
int munmap(void *addr, size_t length);
// addr: 映射地址
// length: 映射长度
// 返回值:成功返回0,失败返回-1
PROT_READ // 可读
PROT_WRITE // 可写
PROT_EXEC // 可执行
PROT_NONE // 不可访问
MAP_SHARED // 共享映射:修改会写回文件,其他进程可见
MAP_PRIVATE // 私有映射:写时复制(COW)
MAP_FIXED // 精确指定地址(危险)
MAP_ANONYMOUS // 匿名映射(不关联文件)
MAP_ANON // MAP_ANONYMOUS别名
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
int main() {
int fd = open("test.txt", O_RDWR | O_CREAT, 0666);
if (fd == -1) {
perror("open");
exit(1);
}
write(fd, "Hello mmap!", 11);
struct stat st;
fstat(fd, &st);
size_t length = st.st_size;
char *mapped = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mapped == MAP_FAILED) {
perror("mmap");
close(fd);
exit(1);
}
close(fd);
printf("Original: %s\n", mapped);
// 修改映射内容(会同步到文件)
strcpy(mapped, "Modified mmap!");
printf("Modified: %s\n", mapped);
// 同步到磁盘
msync(mapped, length, MS_SYNC);
munmap(mapped, length);
return 0;
}
编译命令:
gcc -o mmap_file mmap_file.c
./mmap_file
cat test.txt # 验证文件内容已修改
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
size_t length = 1024;
int flags = MAP_SHARED | MAP_ANONYMOUS;
char *shared = mmap(NULL, length, PROT_READ | PROT_WRITE, flags, -1, 0);
if (shared == MAP_FAILED) {
perror("mmap");
exit(1);
}
pid_t pid = fork();
if (pid == 0) {
// 子进程写入
strcpy(shared, "Hello from child!");
munmap(shared, length);
exit(0);
} else {
// 父进程等待并读取
wait(NULL);
printf("Parent received: %s\n", shared);
munmap(shared, length);
}
return 0;
}
编译命令:
gcc -o mmap_anon mmap_anon.c
./mmap_anon
在嵌入式系统中,常用mmap映射设备寄存器或framebuffer。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
int main() {
int fb_fd = open("/dev/fb0", O_RDWR);
if (fb_fd == -1) {
perror("open framebuffer");
exit(1);
}
struct fb_var_screeninfo vinfo;
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("ioctl");
close(fb_fd);
exit(1);
}
size_t screensize = vinfo.yres_virtual * vinfo.xres_virtual * vinfo.bits_per_pixel / 8;
char *fb = mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
if (fb == MAP_FAILED) {
perror("mmap framebuffer");
close(fb_fd);
exit(1);
}
// 在屏幕中心画一个白点
size_t x = vinfo.xres / 2;
size_t y = vinfo.yres / 2;
size_t location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) +
(y + vinfo.yoffset) * vinfo.line_length;
// 假设32位色深
if (vinfo.bits_per_pixel == 32) {
*(uint32_t*)(fb + location) = 0xFFFFFFFF; // 白色
}
munmap(fb, screensize);
close(fb_fd);
return 0;
}
编译命令:
gcc -o fb_demo fb_demo.c
./fb_demo
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#define GPIO_BASE 0x3F200000 // Raspberry Pi GPIO基地址
#define GPIO_SIZE 0x1000
int main() {
int mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
if (mem_fd == -1) {
perror("open /dev/mem");
exit(1);
}
void *gpio = mmap(NULL, GPIO_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, mem_fd, GPIO_BASE);
if (gpio == MAP_FAILED) {
perror("mmap GPIO");
close(mem_fd);
exit(1);
}
// 读取GPIO状态寄角器(偏移0x34)
volatile uint32_t *gplev0 = (volatile uint32_t*)((char*)gpio + 0x34);
printf("GPIO State: 0x%08X\n", *gplev0);
munmap(gpio, GPIO_SIZE);
close(mem_fd);
return 0;
}
编译命令:
gcc -o gpio_demo gpio_demo.c
sudo ./gpio_demo # 需要root权限访问/dev/mem
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#define SHM_NAME "/my_shared_mem"
#define SEM_NAME "/my_semaphore"
typedef struct {
int value;
sem_t sem;
} shared_data_t;
int main() {
// 创建共享内存
int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, sizeof(shared_data_t));
shared_data_t *shared = mmap(NULL, sizeof(shared_data_t),
PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
// 初始化信号量
sem_init(&shared->sem, 1, 1); // 1: 进程间共享
shared->value = 0;
pid_t pid = fork();
if (pid == 0) {
// 子进程:递增共享变量
for (int i = 0; i < 100000; i++) {
sem_wait(&shared->sem);
shared->value++;
sem_post(&shared->sem);
}
munmap(shared, sizeof(shared_data_t));
exit(0);
} else {
// 父进程:递增共享变量
for (int i = 0; i < 100000; i++) {
sem_wait(&shared->sem);
shared->value++;
sem_post(&shared->sem);
}
wait(NULL);
printf("Final value: %d\n", shared->value);
sem_destroy(&shared->sem);
munmap(shared, sizeof(shared_data_t));
shm_unlink(SHM_NAME);
}
return 0;
}
编译命令:
gcc -o shm_sync shm_sync.c -lrt -lpthread
./shm_sync