更改堆栈空间

目前,我试图在集群系统中实现共享堆栈。 这个系统有两个地址空间,一个是私有的,在所有处理器之间共享。

我怎么能改变在C编程堆栈的开始和结束?

也就是说,我想把堆栈放在一个共享空间中,改变程序的stream程来使用它。

我的建议是:远离传递指向基于堆栈的对象的指针,不惜一切代价。 如果你这样做了,你将需要发送线程永远不会从创建共享对象的函数返回,因为它可以推断 ,没有其他线程将以任何方式访问该对象。 这是a)几乎不可能的,b)需要性能杀死锁定。 没有正确地做到这一点的后果将是完全不确定的错误! 不要这样做!

我会建议malloc 所有对象将离开一个线程的上下文,并使用线程安全引用计数对他们。 您也可以看看线程安全的共享数据结构,如队列,双链表等等。

我怀疑你可以在C中很好地实现你想要的东西(除非你想改变编译器)。

你说你想要一个OpenMP的编程风格。 这相当于一个顶级的线程,它可以让孩子们在父母提供的共享空间上操作。 花式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编译指令所帮助),那么你可以把一个线程的数据分成三部分:

 1. storage accessed only by the thread, and not by its children 2. storage declared by the thread, but accessed only by individual children (eg, slices of arrays) 3. storage read and written by the parent thread and its children 

此时,可以考虑为线程布局“局部变量”,从而为堆栈空间布局。 线程本地存储只分配给父线程的堆栈空间。 父级声明但子级处理的存储空间成为分配给子级本地空间/堆栈的空间。 所有存储读取和写入,可以放在任何可以访问的地方(在父线程的本地空间,在他的堆栈,在堆存储),并将需要访问保护,以防止数据竞争。 [你不能强迫传统的C编译器为你做这件事。]

这种将数据分区到不同的线程本地/堆栈空间使得你明显的使用C的方案,并设置“所有线程堆栈”共享内存中的一个地方很难利用。 如果所有的线程都有相同的堆栈区域,哪个存储是线程本地的? 特别是,如果两个线程都要写入自己的局部变量I,并且我在共享空间中,那么它不是真正的本地。 如果将共享空间分割成不相交的线程堆栈,那么您并不真正共享存储空间,至少不能通过名称共享; 最好你可以使用指针分享到其他线程堆栈。 所有这些都很难编程,因此很容易出错,我不希望为这样的系统编写程序。 它也增加了贵重的共享空间的需求。 你有线程局部变量吃东西,但不需要共享。

如果你有一个固定数量的线程,并继续坚持使用一些可用的C编译器,那么最好是手动分配共享数据(在运行时动态分配,或者在编码/编译时分配共享内存)。 但是你的线程现在可以在本地存储器中运行“标准”堆栈,不需要堆栈切换。

[编辑:在我对仙人掌堆栈评论后,OP想知道更多。 我在这里包括评论,以及一些关于他们的细节的指针]

一个堆栈可以被多个线程共享。 仙人掌堆栈的概念是一个拥有现有(仙人掌)堆栈的父线程与所有并行子进程共享该线程,每个并行子进程都获得自己的堆栈空间,但可以看到/共享父进程的堆栈。

我们的PARLANSE并行编程语言直接实现了这个概念,我们将其用于大约2-4百万行代码的应用程序中。 每个函数调用堆 – 分配它的激活记录(使用线程本地分配器来提高速度),并且可以通过词法级寻址来访问所有的父堆栈段,实现为一个父指针传递给它的子对象的指针呼叫。 下面的英特尔博客描述了我们这样做的原因。

参考文献:

为了清晰起见,请稍微修改一下:

你只是想改变STACK的含义和定义。 根据今天的定义,STACK只能由一个线程使用STACK操作。 进程或线程可以像使用普通内存一样使用STACK。 在这种情况下,你真的应该把这块内存称为“共享内存”而不是“共享堆栈”。 你在集群环境中想要做什么或者做什么?

这是一个例子,为什么STACK不能共享…

线程1函数调用序列:

 main() thr1_f1() thr1_f2() thr1_f3() thr1_f4() 

线程2函数调用序列:

 main() thr2_f1() thr2_f2() thr2_f3() thr2_f4() 

假设这些线程正在共享STACK。 这是一个可能的函数调用序列…

  1. 线程1位于thr1_f1()的中间,在处理器核心-1中进入休眠状态。
  2. 线程2启动并在thr2_f2()的中间,并在处理器core-2中休眠。
  3. 线程1出现并调用thr1_f2()。 这将覆盖线程2堆栈区域。 thr2_f2()的局部变量和参数现在已经搞乱了。
  4. 线程2将无法在thr2_f1()中运行和/或得到它的返回地址。 根据时间的不同,它可能会得到一些地址并转储核心。