c - 具有共享内存和信号量的多个灵活阵列成员或 VLA



我需要定义一个具有两个信号量和三个(至少)或更多数组的结构作为大小为变量的结构的成员。指示性示例(不是正确的语法,而是给出上下文含义;lr是 typedef fordouble):

int nx = 400,ny = 400,nz = 400;
struct ShMem {
sem_t   prod;
sem_t   cons;
lr      u_x[nx+1][ny+2][nz+2];
lr      u_y[nx+2][ny+1][nz+2];
lr      u_z[nx+2][ny+2][nz+2];
};

我需要做的是使结构 ShMem 成为两个代码(又名生产者和消费者)之间的共享内存块,它们在结构中存在的信号量的帮助下计算和读取此内存块。

由于数组大小是变量并且将在运行时定义,因此如何获得三维可变长度数组?

评论: 如果假设我有nxnynz#defined 到 400,我按照以下步骤操作(已经测试过)

#define nx (400)
#define ny (400)
#define nz (400)
struct ShMem {
sem_t   prod;
sem_t   cons;
lr      u_x[nx+1][ny+2][nz+2];
lr      u_y[nx+2][ny+1][nz+2];
lr      u_z[nx+2][ny+2][nz+2];
};
...
// shared memory allocation
ShmID = shmget(ShmKEY, sizeof(struct Shmem), IPC_CREAT|0666);
...

额外的要求是,对于应用程序,我确实需要将这些数组作为 3D 数组,以便我可以将它们索引为u_x[i][j][k]、whreijk分别是 x、y 和 z 方向的索引。

在伦丁和菲利克斯解决方案之后编辑。

约束 -u_xu_yu_z需要是一个 3D 数组/*** 指针,u_x[i][j][k]访问该指针 - 这无法更改,因为这是遗留代码。需要设置数组,以保持访问的神圣性。代码中的任何地方都是这样访问的。

正如评论中已经讨论过的,C 不支持这样的东西。因此,您必须自己构建它。一个简单的示例使用宏使结构内的"3D 访问"可读,如下所示:

#include <stdlib.h>
typedef int lr;
struct foo {
size_t ny;
size_t nz;
lr *u_y;
lr *u_z;
lr u_x[];
};
#define val(o, a, x, y, z) ((o).a[(o).ny * (o).nz * x + (o).nz * y + z])
struct foo *foo_create(size_t nx, size_t ny, size_t nz)
{
size_t arrsize = nx * ny * nz;
struct foo *obj = malloc(sizeof *obj + 3 * arrsize * sizeof *(obj->u_x));
if (!obj) return 0;
obj->ny = ny;
obj->nz = nz;
obj->u_y = obj->u_x + arrsize;
obj->u_z = obj->u_y + arrsize;
return obj;
}
int main(void)
{
struct foo *myFoo = foo_create(10, 10, 10);
// set u_y[9][5][2] in *myFoo to 42:
val(*myFoo, u_y, 9, 5, 2) = 42;
free(myFoo);
}

这使用 C 支持的结构末尾的单个 FAM,因此您可以在单个块中分配此类结构。要将其放置在共享内存中,只需更换malloc()并使用相同的大小计算。

你必须构建这样的东西

struct ShMem {
int some_stuff_here;
size_t x[3];
size_t y[3];
size_t z[3];
int array[];
};

然后忽略灵活数组成员类型是普通 int 数组。而是做类似的事情

size_t size = sizeof( int[x1][y1][z1] ) +
sizeof( int[x2][y2][z2] ) +
sizeof( int[x3][y3][z3] );
ShMem* shmem = malloc(sizeof *shmem + size);

然后在访问时,您使用数组指针类型而不是int[]。代码读起来有点讨厌:

for(size_t i=0; i<3; i++)
{
typedef int(*arr_t)[shmem->y[i]][shmem->z[i]]; // desired array pointer type
int some_offset = ... // calculate based on previously used x y z
arr_t arr = (arr_t)shmem->(array + some_offset); // cast to the array pointer type
for(size_t x=0; x<shmem->x[i]; x++)
{
for(size_t y=0; y<shmem->y[i]; y++)
{
for(size_t z=0; z<shmem->z[i]; z++)
{
arr[x][y][z] = something;
}
}
}
}

这实际上是明确定义的行为,因为使用 malloc 分配的数据在您访问它之前没有有效的类型。

上面示例中的"some_offset"可以是计数器变量或存储在结构本身内部的内容。

最新更新