我正试图共享这样的结构
例子:

typedef struct {
    int* a;
    int b;
    int c;
} ex;

在进程之间,问题是当我用malloc初始化“a”时,它对执行此操作的进程堆是私有的(或者至少我认为这是发生的事情)。有没有办法用这个结构来创建一个共享内存(使用shmget、shmat)?
编辑:我在Linux上工作。
编辑:我有一个初始化缓冲区的过程,如下所示:
key_t key = ftok("gr", 'p');
int mid = shmget(key, sizeof(ex), IPC_CREAT | 0666);
ex* e = NULL;
status b_status = init(&e, 8); //init gives initial values to b c and allocate space for 'a' with a malloc
e = (ex*)shmat(mid, NULL, 0);

另一个进程将自己连接到共享内存中,如下所示:
key_t key = ftok("gr", 'p');
int shmid = shmget(key, sizeof(ex), 0);
ex* e;
e = (ex*)shmat(shmid, NULL, 0);

然后从a中得到一个元素,在这种情况下,在位置1中
int i = get_el(e, 1);

最佳答案

首先,要共享int *a字段指向的内容,需要复制与之相关的整个内存。因此,您需要一个至少可以保存size_t shm_size = sizeof(struct ex) + get_the_length_of_your_ex();的共享内存。
从现在开始,既然您提到了shmget和shmat,我假设您运行的是Linux系统。
第一步是创建共享内存段。如果可以确定int *a内容大小的上限,这将是一件好事。这样就不必反复创建/删除共享内存段。但是如果这样做,就需要额外的开销来说明实际数据需要多长时间。我假设一个简单的size_t就可以实现这个目的。
然后,在创建段之后,必须正确设置数据,使其保持所需的状态。注意,虽然内存段的物理地址总是相同的,但是当调用shmat时,您将得到虚拟指针,这些指针只在调用shmat的进程中可用。下面的示例代码应该为您提供一些技巧。

#include <sys/types.h>
#include <sys/ipc.h>

/* Assume a cannot point towards an area larger than 4096 bytes. */
#define A_MAX_SIZE (size_t)4096

struct ex {
    int *a;
    int b;
    int c;
}

int shm_create(void)
{
    /*
     * If you need to share other structures,
     * You'll need to pass the key_t as an argument
     */
    key_t k = ftok("/a/path/of/yours");
    int shm_id = 0;
    if (0 > (shm_id = shmget(
        k, sizeof(struct ex) + A_MAX_SIZE + sizeof(size_t), IPC_CREAT|IPC_EXCL|0666))) {
        /* An error occurred, add desired error handling. */
    }
    return shm_id;
}

/*
 * Fill the desired shared memory segment with the structure
 */
int shm_fill(int shmid, struct ex *p_ex)
{
    void *p = shmat(shmid, NULL, 0);
    void *tmp = p;
    size_t data_len = get_my_ex_struct_data_len(p_ex);
    if ((void*)(-1) == p) {
        /* Add desired error handling */
        return -1;
    }
    memcpy(tmp, p_ex, sizeof(struct ex));
    tmp += sizeof(struct ex);
    memcpy(tmp, &data_len, sizeof(size_t);
    tmp += 4;
    memcpy(tmp, p_ex->a, data_len);

    shmdt(p);
    /*
     * If you want to keep the reference so that
     * When modifying p_ex anywhere, you update the shm content at the same time :
     * - Don't call shmdt()
     * - Make p_ex->a point towards the good area :
     * p_ex->a = p + sizeof(struct ex) + sizeof(size_t);
     * Never ever modify a without detaching the shm ...
     */
    return 0;
}

/* Get the ex structure from a shm segment */
int shm_get_ex(int shmid, struct ex *p_dst)
{
    void *p = shmat(shmid, NULL, SHM_RDONLY);
    void *tmp;
    size_t data_len = 0;
    if ((void*)(-1) == p) {
        /* Error ... */
        return -1;
    }
    data_len = *(size_t*)(p + sizeof(struct ex))
    if (NULL == (tmp = malloc(data_len))) {
        /* No memory ... */
        shmdt(p);
        return -1;
    }
    memcpy(p_dst, p, sizeof(struct ex));
    memcpy(tmp, (p + sizeof(struct ex) + sizeof(size_t)), data_len);
    p_dst->a = tmp;
    /*
     * If you want to modify "globally" the structure,
     * - Change SHM_RDONLY to 0 in the shmat() call
     * - Make p_dst->a point to the good offset :
     * p_dst->a = p + sizeof(struct ex) + sizeof(size_t);
     * - Remove from the code above all the things made with tmp (malloc ...)
     */
    return 0;
}

/*
 * Detach the given p_ex structure from a shm segment.
 * This function is useful only if you use the shm segment
 * in the way I described in comment in the other functions.
 */
void shm_detach_struct(struct ex *p_ex)
{
    /*
     * Here you could :
     * - alloc a local pointer
     * - copy the shm data into it
     * - detach the segment using the current p_ex->a pointer
     * - assign your local pointer to p_ex->a
     * This would save locally the data stored in the shm at the call
     * Or if you're lazy (like me), just detach the pointer and make p_ex->a = NULL;
     */

    shmdt(p_ex->a - sizeof(struct ex) - sizeof(size_t));
    p_ex->a = NULL;
}

请原谅我的懒惰,因为它在共享内存中是完全未使用过的,所以不复制struct ex的int *a指针的所有值是空间优化的,但是我为自己保留了额外的代码来处理这个问题(以及一些指针检查,如p eu ex参数完整性)。
但是,完成后,您必须找到一种方法在进程之间共享SHM ID。这可以通过使用插座、管道…或者使用相同输入的ftok

07-24 09:46
查看更多