Linux下用C语言检测文件是否被其他进程映射的方法
Linux下mmap共享Bitmap的进程崩溃后资源回收方案
针对你用mmap实现多进程共享Bitmap、进程崩溃后资源位无法自动清除的问题,核心解决思路是给每个资源位绑定占用进程的PID,通过检测PID存活状态来回收僵尸资源,以下是具体实现方案:
1. 扩展共享内存结构
原Bitmap只记录资源是否被占用,现在需要额外维护一个PID数组,每个元素对应Bitmap的一位,存储占用该资源的进程ID(0表示未占用)。同时加入进程间互斥锁,保证所有操作的原子性:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <pthread.h> #include <signal.h> #include <errno.h> #define RESOURCE_COUNT 100 // 自定义资源总数 #define SHARED_FILE "/tmp/shared_resource_map" // 共享映射文件路径 typedef struct { pthread_mutex_t mutex; // 进程间共享互斥锁 unsigned char bitmap[RESOURCE_COUNT / 8 + 1]; // 资源占用位图 pid_t resource_owners[RESOURCE_COUNT]; // 每个资源对应的占用进程PID } SharedResourceMap;
2. 初始化共享映射
创建并映射共享文件,同时初始化互斥锁和共享结构的初始状态:
SharedResourceMap* init_shared_map() { int fd = open(SHARED_FILE, O_CREAT | O_RDWR, 0666); if (fd == -1) { perror("open shared file failed"); return NULL; } // 扩展文件到结构体大小 struct stat st; if (fstat(fd, &st) == -1) { perror("fstat failed"); close(fd); return NULL; } if (st.st_size < sizeof(SharedResourceMap)) { if (ftruncate(fd, sizeof(SharedResourceMap)) == -1) { perror("ftruncate failed"); close(fd); return NULL; } } // 映射到进程内存空间 SharedResourceMap* map = mmap(NULL, sizeof(SharedResourceMap), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (map == MAP_FAILED) { perror("mmap failed"); return NULL; } // 仅第一次创建时初始化锁和结构 static int is_initialized = 0; if (!is_initialized) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); // 设置为进程间共享 pthread_mutex_init(&map->mutex, &attr); pthread_mutexattr_destroy(&attr); // 初始化位图和PID数组为0 for (int i = 0; i < RESOURCE_COUNT; i++) { map->resource_owners[i] = 0; int byte_idx = i / 8; int bit_idx = i % 8; map->bitmap[byte_idx] &= ~(1 << bit_idx); } is_initialized = 1; } return map; }
3. 僵尸资源清理逻辑
通过kill(pid, 0)检测进程存活状态(该调用仅检查PID是否存在,不发送任何信号),如果进程已死则回收对应资源:
void cleanup_dead_resources(SharedResourceMap* map) { pthread_mutex_lock(&map->mutex); for (int i = 0; i < RESOURCE_COUNT; i++) { pid_t pid = map->resource_owners[i]; if (pid == 0) continue; // 检查进程是否存活:返回-1且errno=ESRCH表示进程不存在 if (kill(pid, 0) == -1) { if (errno == ESRCH) { int byte_idx = i / 8; int bit_idx = i % 8; map->bitmap[byte_idx] &= ~(1 << bit_idx); map->resource_owners[i] = 0; printf("Cleaned resource %d (dead PID: %d)\n", i, pid); } } } pthread_mutex_unlock(&map->mutex); }
4. 资源申请与释放
申请资源前先清理僵尸资源,保证可用资源的准确性;释放资源时同步清理位图和PID记录:
// 申请资源,返回资源索引,失败返回-1 int allocate_resource(SharedResourceMap* map) { cleanup_dead_resources(map); pthread_mutex_lock(&map->mutex); for (int i = 0; i < RESOURCE_COUNT; i++) { int byte_idx = i / 8; int bit_idx = i % 8; if (!(map->bitmap[byte_idx] & (1 << bit_idx))) { map->bitmap[byte_idx] |= (1 << bit_idx); map->resource_owners[i] = getpid(); pthread_mutex_unlock(&map->mutex); return i; } } pthread_mutex_unlock(&map->mutex); return -1; } // 释放指定索引的资源 void release_resource(SharedResourceMap* map, int res_idx) { if (res_idx < 0 || res_idx >= RESOURCE_COUNT) return; pthread_mutex_lock(&map->mutex); int byte_idx = res_idx / 8; int bit_idx = res_idx % 8; map->bitmap[byte_idx] &= ~(1 << bit_idx); map->resource_owners[res_idx] = 0; pthread_mutex_unlock(&map->mutex); }
关键注意事项
- 互斥锁属性:必须设置
PTHREAD_PROCESS_SHARED,否则其他进程无法识别该锁,会导致竞态条件。 - 权限问题:
kill(pid, 0)对root进程会返回EPERM(表示进程存活但无权限发送信号),不要误判为进程已死,只在errno == ESRCH时判定进程死亡。 - 性能优化:如果业务进程频繁申请资源,每次遍历清理会有开销,可以单独启动一个后台监控进程,每隔固定时间调用
cleanup_dead_resources,业务进程无需每次清理。 - 文件权限:共享文件要设置合适的权限(如0666),确保所有需要访问的进程都能读写。
内容的提问来源于stack exchange,提问作者HnlyWk
相关产品推荐
相关产品推荐

