首页 > 解决方案 > 具有指针的共享内存数据结构

问题描述

您好我正在尝试使用共享内存 IPC 在进程之间进行通信。但是,当我尝试使用 shmat 来分配指向数据结构的指针时,它会返回共享内存地址的起始地址。我的代码如下

#define SHM_SIZE 10240
struct myds {
 int ind;
 char *data[1];
};
int main()
{

    key_t key = ftok("shmfile",65);
    struct myds *nums;

    int shmid = shmget(key,SHM_SIZE,0666|IPC_CREAT);

    char *shm_addr = (char*) shmat(shmid,(void*)0,0);
    int *count = (int *) shm_addr;
    *count = 5;
    nums = (struct myds *)((void *)shm_addr + sizeof(int));
    for(int i = 0; i < *count; i++) {
         nums[i].ind = i;
    }
    
    char *t = (char*) shmat(shmid,(void*)0,0);
    printf("%d\n", *count);
    sprintf(t, "check- 112\0");
    nums[0].data[0] = t;
    printf("Data written in memory:");

    getc(stdin);
    printf("%d\n", *count);

    shmdt(shm_addr);
    shmctl(shmid,IPC_RMID,NULL);

    return 0;
}

*count 的最后一次打印应该打印 5,而是打印一些不同且非常大的值。这似乎是 sprintf(t, "check-112\0") 的效果。我在这里做错了吗?

标签: pointersshared-memory

解决方案


countt指向相同的内存地址。当sprintf()通过 向该地址写入新数据时t,它会覆盖正在通过 读取的值*count。这就是为什么你会从*countafter中得到垃圾sprintf()

看起来您正在尝试将sprintf()数据写入 指向的内存nums[0].data[0],但实际上您并没有设置data[0]指向任何有意义的地方。返回的起始地址shmat()是错误的存储地址data[0]

由于您正在分配一个非常大的内存块,比myds实际需要的 5 个结构的数组要多得多,因此您可以指向数组data[0]中最后分配myds的结构之后的内存。

尝试更多类似的东西:

#define SHM_COUNT 5

struct myds {
    int ind;
    char* data[1];
};

int main()
{
    key_t key = ftok("shmfile",65);
    struct myds *nums;

    int shmid = shmget(key, sizeof(int) + (sizeof(struct myds) * SHM_COUNT) + 11, 0666|IPC_CREAT);

    char *shm_addr = (char*) shmat(shmid, NULL, 0);
    int *count = (int *) shm_addr;
    *count = SHM_COUNT;

    nums = (struct myds *)(shm_addr + sizeof(int));
    for(int i = 0; i < SHM_COUNT; i++) {
        nums[i].ind = i;
    }

    char *t = (char*) (nums + SHM_COUNT);
    printf("%d\n", *count);
    sprintf(t, "check- 112\0");

    for(int i = 0; i < SHM_COUNT; i++) {
        nums[i].data[0] = t;
    }

    printf("Data written in memory:");

    getc(stdin);
    printf("%d\n", *count);

    shmdt(shm_addr);
    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

然后其他进程可以简单地使用char*存储在其中的指针nums[i].data[0]来访问每个nums[]元素的字符串。

如果您想为每个nums[]元素添加不同的字符串,只需分配足够的共享内存来保存所有字符串,然后nums[i].data[0]在该内存中相应地指向。


更新:如果存储char*指针对您不起作用,则改为存储偏移量,例如:

#define SHM_COUNT 5

struct myds {
    int ind;
    size_t data_offset[1];
};

int main()
{
    key_t key = ftok("shmfile",65);
    struct myds *nums;

    int shmid = shmget(key, sizeof(int) + (sizeof(struct myds) * SHM_COUNT) + 11, 0666|IPC_CREAT);

    char *shm_addr = (char*) shmat(shmid, NULL, 0);
    int *count = (int *) shm_addr;
    *count = SHM_COUNT;

    nums = (struct myds *)(shm_addr + sizeof(int));
    for(int i = 0; i < SHM_COUNT; i++) {
        nums[i].ind = i;
    }

    char *t = (char*) (nums + SHM_COUNT);
    printf("%d\n", *count);
    sprintf(t, "check- 112\0");

    for(int i = 0; i < SHM_COUNT; i++) {
        nums[0].data_offset[0] = (t - shm_addr);
    }

    printf("Data written in memory:");

    getc(stdin);
    printf("%d\n", *count);

    shmdt(shm_addr);
    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

然后其他进程可以简单地添加nums[i].data_offset[0]到它们的本地shm_addr地址以访问每个nums[]元素的字符串。


推荐阅读