我怀疑你能否在 C 中很好地实现你想要的(除非你想改变编译器)。
您说您想要一种 OpenMP 风格的编程。这相当于一个顶级线程,可以分叉子级以在父级提供的共享空间上进行操作。 Fancy OpenMP 以递归方式执行此操作。
要做到这一点很好,你的系统/工具/编译器需要能够识别
* threads of computations
* what variables are declared by each thread
* what variables (or parts thereof) are offered by a thread to its thread children
如果您可以做到这些(并且通过显式语言支持更容易,启用 OpenMP 的编译器在此过程中由 OpenMP 编译指示辅助),那么您可以将线程的数据分成 3 个部分:
1. storage accessed only by the thread, and not by its children
2. storage declared by the thread, but accessed only by individual children (e.g., slices of arrays)
3. storage read and written by the parent thread and its children
此时,您可以考虑为线程布局“局部变量”,从而获得堆栈空间。
线程本地存储仅分配给父线程的堆栈空间。父声明但子处理的存储成为分配给子本地空间/堆栈的空间。所有人都可以读写的存储可以放置在可以访问的任何地方(在父线程的本地空间中,在他的堆栈中,在堆存储中),并且需要访问保护以防止数据竞争。 [你不能强迫传统的 C 编译器为你做这件事。]
这种将数据划分到不同线程本地/堆栈空间的做法使您使用 C 并将“所有线程堆栈”设置为 一个 的明显方案在共享内存中难以驾驭。如果所有线程都具有相同的堆栈区域,那么哪个存储是线程本地的?特别是,如果两个线程都想写入自己的局部变量 I,并且 I 在共享空间中,那么它就不是真正的局部变量。如果您将共享空间划分为不相交的线程堆栈,那么您实际上并没有共享存储空间,至少没有按名称共享;充其量您可以使用指向其他线程堆栈的指针进行共享。所有这些都很难编程,因此容易出错,我不想调试为这样的系统编写的程序。它还对您宝贵的共享空间提出了额外的要求;你有线程局部变量吃掉它,但不需要共享。
如果您有一个静态数量的线程,并继续坚持使用一些可用的 C 编译器,您最好手动分配共享数据(在运行时动态分配,或者在编码/编译时通过分区共享内存)。但是您的线程现在可以使用其本地内存中的“标准”堆栈运行,并且不需要堆栈切换。
[编辑:在我对仙人掌堆发表评论后,OP 想了解更多。我包括
此处的评论,以及一些指向有关它们的详细信息的指针]
一个栈可以被多个线程共享。 仙人掌堆栈的概念是这样一个概念,其中一个父线程拥有一个现有的(仙人掌)堆栈,与所有并行子线程共享该堆栈,每个子线程都有自己的堆栈空间,但可以看到/共享父堆栈。
我们的 PARLANSE 并行编程语言直接实现了这个概念,我们在大约 2-4 百万行代码的应用程序中使用它。每个函数调用堆分配
它的激活记录(使用线程本地分配器来提高速度),并且可以通过词法级向上寻址访问所有父堆栈段,实现为在函数调用上由父传递给其子的指针框。下面的英特尔博客准确地描述了我们这样做的原因。
参考资料: