进程间共享内存值不一致问题:代码实现与故障排查问询
共享内存内容不一致问题排查
我用以下函数创建共享内存缓冲区:
int create_buffer(const char *shmem_name, void **shmem_obj) { int returnval = 0; int fd; fd = shm_open(shmem_name, O_CREAT | O_RDWR, 0666); ftruncate(fd, sizeof(ShareStruct)); *shmem_obj = (ShareStruct *)mmap(NULL, sizeof(ShareStruct), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (shmem_obj < 0) { returnval = -1; } return returnval; }
进程1中使用该指针及相关函数一切正常,但进程2通过以下函数获取缓冲区后,内容出现异常值:
int fetch_buffer(const char *shmem_name, void **shmem_obj) { int returnval = 0; int fd; fd = shm_open(shmem_name, O_RDWR, 0666); ftruncate(fd, sizeof(ShareStruct)); *shmem_obj = (ShareStruct *)mmap(NULL, sizeof(ShareStruct), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (shmem_obj < 0) { returnval = -1; } printf("buffer fetched \n"); return returnval; }
补充代码
进程1代码
#define SHMEM_NAME "OS" int main(void) { int exitcode = 0; void *shmem_obj; /* Initialize the buffer and create the shared memory */ if( create_buffer(SHMEM_NAME, &shmem_obj) != 0) { fprintf(stderr, "Something went wrong while initializing the buffer.\n"); exitcode = 1; } else { printf("Shared buffer created.\n"); initParameters(&shmem_obj); subscribe(0, &shmem_obj); printf("\n[PRESS ENTER TO CLOSE THE SHARED BUFFER]"); getchar(); /* unlink the shared memory */ if(destroy_buffer(SHMEM_NAME) != 0) { fprintf(stderr, "Something went wrong while destroying the buffer.\n"); exitcode = 2; } else { printf("Shared buffer closed.\n"); } } return exitcode; }
进程2代码
#define SHMEM_NAME "OS" int main(void) { void *shmem_obj; /* fetch the buffer from shared memory */ fetch_buffer(SHMEM_NAME, &shmem_obj); subscribe(1, &shmem_obj); printf("Subscriber 0 subscribed\n"); }
其他相关代码
typedef struct ShareStruct { Subscriber subscriberList[20]; int subscriberActiveList[20]; unsigned int writepointer_tail; unsigned int readpointer_head; Task taskList[21]; sem_t freePostions; pthread_mutex_t mutex; unsigned int subscriberCount; } ShareStruct; int initParameters(void *shmem_obj) { ShareStruct *shmem = shmem_obj; int returnval = 0; shmem->writepointer_tail = 0; shmem->readpointer_head = 0; shmem->subscriberCount = 0; pthread_mutex_init(&shmem->mutex, NULL); sem_init(&shmem->freePostions, 1, 20); return returnval; } int destroy_buffer(const char *shmem_name) { int returnval = 0; returnval = shm_unlink(shmem_name); return returnval; } int subscribe(subscriber_id subscriber, void *shmem_obj) { int returnval = 0; ShareStruct *shmem = shmem_obj; int value; sem_getvalue(&shmem->freePostions, &value); printf("sem value : %d\n", value); pthread_mutex_lock(&shmem->mutex); int freeposition = returnNextFreePosition(shmem_obj); if (freeposition != -1) { printf("subscribe logic"); } else { printf("Subscriber list is full \n"); } pthread_mutex_unlock(&shmem->mutex); return returnval; }
问题根源及修正方案
1. 参数传递类型不匹配
进程1和进程2调用initParameters、subscribe时,传递的是&shmem_obj(void**类型),但这两个函数的形参是void*。强制类型转换后会访问错误的内存地址,导致读取到异常值。
修正:直接传递shmem_obj而非其地址:
- 进程1中改为:
initParameters(shmem_obj)、subscribe(0, shmem_obj) - 进程2中改为:
subscribe(1, shmem_obj)
2. 错误的mmap返回值检查逻辑
create_buffer和fetch_buffer中,判断shmem_obj < 0是错误的——shmem_obj是指针的指针,应该检查*shmem_obj(mmap的返回值)是否等于MAP_FAILED。
修正:
if (*shmem_obj == MAP_FAILED) { returnval = -1; }
需确保包含头文件<sys/mman.h>以获取MAP_FAILED定义。
3. fetch_buffer中不必要的ftruncate调用
进程2调用ftruncate会覆盖进程1已初始化的共享内存内容,导致数据丢失。共享内存的大小应由创建它的进程(进程1)设置,其他进程只需映射即可。
修正:移除fetch_buffer中的ftruncate(fd, sizeof(ShareStruct));语句。
4. 文件描述符未关闭
shm_open返回的文件描述符在mmap后未关闭,会造成资源泄漏。
修正:在mmap成功后添加close(fd);语句。
5. 进程同步问题
需确保进程1完成共享内存初始化后,再启动进程2。否则进程2会访问未初始化的内存,读取到异常值。可通过信号量等同步机制保证执行顺序。
修正后的关键代码示例
修正后的create_buffer
#include <sys/mman.h> #include <fcntl.h> #include <unistd.h> int create_buffer(const char *shmem_name, void **shmem_obj) { int returnval = 0; int fd = shm_open(shmem_name, O_CREAT | O_EXCL | O_RDWR, 0666); if (fd == -1) { returnval = -1; return returnval; } if (ftruncate(fd, sizeof(ShareStruct)) == -1) { close(fd); shm_unlink(shmem_name); returnval = -1; return returnval; } *shmem_obj = mmap(NULL, sizeof(ShareStruct), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (*shmem_obj == MAP_FAILED) { shm_unlink(shmem_name); returnval = -1; } return returnval; }
修正后的fetch_buffer
int fetch_buffer(const char *shmem_name, void **shmem_obj) { int returnval = 0; int fd = shm_open(shmem_name, O_RDWR, 0666); if (fd == -1) { returnval = -1; return returnval; } *shmem_obj = mmap(NULL, sizeof(ShareStruct), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (*shmem_obj == MAP_FAILED) { returnval = -1; } printf("buffer fetched \n"); return returnval; }
内容的提问来源于stack exchange,提问作者Karel Debedts
相关产品推荐
相关产品推荐

