C 具有共享内存和信号量的多个灵活数组成员或VLA

C 具有共享内存和信号量的多个灵活数组成员或VLA,c,arrays,memory,semaphore,shared-memory,C,Arrays,Memory,Semaphore,Shared Memory,我需要定义一个具有两个信号量和三个(至少)或更多数组的结构,作为其大小为变量的结构的成员。指示性示例(不是正确的语法,而是给出上下文含义;lr是double的typedef): 我需要做的是使struct ShMem成为两个代码(即生产者和消费者)之间的共享内存块,这两个代码在struct中存在的信号量的帮助下计算和读取这个内存块 由于数组大小是变量,将在运行时定义,如何获得三维可变长度数组 评论: 如果假设我有nx、ny和nz#定义d到400,我遵循以下步骤(已测试) 附加要求是,对于应用程序

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

我需要做的是使struct ShMem成为两个代码(即生产者和消费者)之间的共享内存块,这两个代码在struct中存在的信号量的帮助下计算和读取这个内存块

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

评论: 如果假设我有
nx
ny
nz
#定义
d到400,我遵循以下步骤(已测试)

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

在Lundin和Felix解决方案之后编辑


约束-
u_x
u_y
u_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);
}
#包括
typedef int-lr;
结构foo{
大小;;
尺寸(新西兰);;
lr*u_y;
lr*uz;
lr u_x[];
};
#定义val(o,a,x,y,z)((o).a[(o).ny*(o).nz*x+(o).nz*y+z])
结构foo*foo\u创建(大小nx、大小ny、大小nz)
{
尺寸=nx*ny*nz;
struct foo*obj=malloc(sizeof*obj+3*arrsize*sizeof*(obj->u_x));
如果(!obj)返回0;
obj->ny=ny;
obj->nz=nz;
obj->u_y=obj->u_x+arrsize;
obj->u_z=obj->u_y+arrsize;
返回obj;
}
内部主(空)
{
struct foo*myFoo=foo_create(10,10,10);
//将*myFoo中的u_y[9][5][2]设置为42:
val(*myFoo,u_y,9,5,2)=42;
免费(myFoo);
}

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

您必须构建类似的内容

struct ShMem {
  int some_stuff_here;
  size_t x[3];
  size_t y[3];
  size_t z[3];
  int array[];
};
然后忽略flexible数组成员类型是普通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;
      }
    }
  }
}
for(size_t i=0;iy[i][shmem->z[i]];//所需的数组指针类型
int some_offset=…//根据以前使用的x y z计算
arr\u t arr=(arr\u t)shmem->(数组+某些偏移);//强制转换为数组指针类型
对于(大小x=0;xx[i];x++)
{
对于(大小y=0;yy[i];y++)
{
对于(大小_t z=0;zz[i];z++)
{
arr[x][y][z]=某物;
}
}
}
}
这实际上是一种定义良好的行为,因为分配给malloc的数据在您访问它之前没有有效的类型


上例中的“some_offset”可以是一个计数器变量或存储在结构本身内部的东西。

为什么不使用指向动态分配的指针,这些动态分配可以是索引行、列、层样式,例如
u x[i+j*cols+k*cols*rows]
?@DavidBowling是合理的,但这只是一个设计决策,因为在使用共享内存的两个代码中,有一个是许多人使用的leagacy代码。因此,为了代码可读性和易于理解,需要具有类似的语义。这3个数组是否需要相邻分配,或者如果它们在共享内存中,这就足够了?这没关系,它们需要与两个信号量一起位于共享内存中。将它们作为连续内存块不是一个限制。你要求的是语言无法做到的事情。为了可读性,为什么不使用大型动态分配(或结构末尾的FAM),指向“3D访问”的相应开始和一些访问器函数或宏?答案非常正确,但不满足我更明确的约束条件。(检查问题的编辑)@datapanda这个答案并不矛盾——只是在上面的示例中我将指针设置为本地,因为指向VLA的指针不能是结构的成员。现在,如果旧的遗留代码没有VLA,并且您希望更改为VLA,那么这将不起作用。最坏的情况是,您可以将上述解决方案与icky宏一起使用。您不能完全更改代码,同时保持原样……答案很正确,但它不满足我更明确的约束条件。(检查问题的编辑)@datapanda再说一遍,这是不可能的。你不能改变语言。很抱歉在这里提供帮助……我觉得我让它有点混乱,我的直觉告诉我这是非常可行的。你能看看建立3D矩阵的要点吗。我所需要的是使用信号量使它与种族条件保护者共享。@datapanda这绝对不是一个3d数组,它是指向指向指针的指针。好吧,这是我想要的,可能术语不同,但与我所理解的“指向指针的指针”已经编码,使得第9行定义的内存块看起来像一个3d数组。
size_t size = sizeof( int[x1][y1][z1] ) +
              sizeof( int[x2][y2][z2] ) +
              sizeof( int[x3][y3][z3] );

ShMem* shmem = malloc(sizeof *shmem + size);
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;
      }
    }
  }
}