You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

进程间共享内存值不一致问题:代码实现与故障排查问询

共享内存内容不一致问题排查

我用以下函数创建共享内存缓冲区:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 11:50:23