如何查询关联System V共享内存的进程数?及写冲突检测方法
System V共享内存:1写N读模型的互斥实现及关联进程数查询
一、避免多进程同时写入的实现方案
针对1写N读模型,核心是保证同一时间只有一个写进程操作共享内存,以下是几种可靠实现方式:
1. System V二元信号量(推荐)
利用System V信号量实现互斥锁,和共享内存同属一套IPC机制,集成性好:
// 初始化信号量(仅需执行一次,比如由第一个启动的进程完成) #include <sys/sem.h> #include <sys/ipc.h> union semun { int val; struct semid_ds *buf; unsigned short *array; }; key_t sem_key = ftok("/tmp/shm_sem", 'W'); int sem_id = semget(sem_key, 1, IPC_CREAT | 0666); union semun init_arg; init_arg.val = 1; // 二元信号量初始值设为1 semctl(sem_id, 0, SETVAL, init_arg); // 写进程获取锁 struct sembuf lock_op = {0, -1, SEM_UNDO}; semop(sem_id, &lock_op, 1); // --- 开始写入共享内存 --- // ... 你的写入逻辑 ... // --- 写入结束 --- // 释放锁 struct sembuf unlock_op = {0, 1, SEM_UNDO}; semop(sem_id, &unlock_op, 1);
SEM_UNDO选项会在进程异常退出时自动释放信号量,避免死锁。
2. 共享内存内的原子变量
在共享内存头部嵌入原子整数,通过原子CAS操作实现互斥,无需额外IPC资源:
#include <stdatomic.h> #include <sys/shm.h> // 定义共享内存结构 typedef struct { _Atomic int write_in_progress; // 0=无写入,1=正在写入 char data[4096]; // 实际存储的数据 } ShmBlock; // 写进程尝试获取写入权限 int shm_id = shmget(shm_key, sizeof(ShmBlock), 0666); ShmBlock *shm_ptr = shmat(shm_id, NULL, 0); int expected = 0; if (atomic_compare_exchange_strong(&shm_ptr->write_in_progress, &expected, 1)) { // 获取到写入权限,执行操作 memcpy(shm_ptr->data, "your_data", strlen("your_data")+1); // 操作完成后重置标记 atomic_store(&shm_ptr->write_in_progress, 0); } else { // 已有其他写进程在运行,执行重试或报错逻辑 }
该方式依赖C11标准的原子操作,Linux下GCC/Clang均支持。
3. 文件锁(简单易用)
通过文件独占锁实现互斥,无需依赖System V信号量,适合快速原型开发:
#include <fcntl.h> #include <unistd.h> // 写进程获取锁 int lock_fd = open("/tmp/shm_write_lock", O_CREAT | O_RDWR, 0666); struct flock write_lock = { .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 0 // 锁定整个文件 }; // 阻塞等待获取锁,非阻塞可用F_SETLK fcntl(lock_fd, F_SETLKW, &write_lock); // --- 写入共享内存 --- // ... 你的写入逻辑 ... // --- 写入结束 --- // 释放锁 write_lock.l_type = F_UNLCK; fcntl(lock_fd, F_SETLK, &write_lock); close(lock_fd);
二、查询共享内存关联的进程数量
Linux系统提供了两种方式获取System V共享内存的关联进程数(即nattch值):
1. 解析/proc/sysvipc/shm文件
该文件记录了所有System V共享内存的元数据,直接读取解析即可:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> int get_shm_attached_count(key_t shm_key) { FILE *fp = fopen("/proc/sysvipc/shm", "r"); if (!fp) return -1; char line[256]; // 跳过表头行 fgets(line, sizeof(line), fp); while (fgets(line, sizeof(line), fp)) { key_t current_key; int nattch; // 按文件格式解析,注意不同内核版本格式可能略有差异 if (sscanf(line, "%*d %x %*d %*d %*d %*d %d", ¤t_key, &nattch) == 2) { if (current_key == shm_key) { fclose(fp); return nattch; } } } fclose(fp); return -1; // 未找到对应共享内存 }
2. 调用ipcs命令解析输出
通过popen()执行ipcs -m命令,再解析输出结果,适合脚本或快速调试:
# shell命令示例,替换为你的共享内存key(十六进制) ipcs -m | grep <your_shm_key> | awk '{print $6}'
在C程序中可以通过popen()调用并读取输出,逻辑类似文件解析。
内容的提问来源于stack exchange,提问作者kevin h
相关产品推荐
相关产品推荐

