まず、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;
}
私の怠惰を許してください、共有メモリでは完全に使用されていないため、構造体exint *a
のポインターの値をまったくコピーしないようにスペースが最適化されますが、これを処理するために余分なコードを節約しました(およびいくつかのポインターチェックp_ex 引数の整合性)。
ただし、完了したら、プロセス間で shm ID を共有する方法を見つける必要があります。これは、ソケット、パイプを使用して行うことができます...またはftok
同じ入力で使用します。