3

我正在使用 setjmp() 和 longjmp() 在 c 中编写一个多线程环境来在线程之间切换。

我不确定如何最好地为每个线程分配堆栈空间。这必须在更大规模的线程环境中动态完成,但我想不出一种方法来跟踪线程正在使用多少堆栈以更改分配的数量。

我可以像这样在堆栈的各个部分之间预先分配静态空间量:

void call_with_cushion (void) {
    char space[1000]; 
    space[999] = 1; /* Do not optimize array out of existence */
    child();
}

(来自维基百科http://en.wikipedia.org/wiki/Setjmp.h的代码片段)

但这似乎超出了灵活性,我只是想知道多线程环境通常如何为每个线程分配内存?

谢谢

4

2 回答 2

5

通常,分配给线程的最大堆栈空间量在创建线程时是固定的,如果线程超过此限制,则结果是未定义的行为——没有办法将堆栈空间增加到超过该限制。如果幸运的话,堆栈溢出会导致某种堆栈溢出异常或信号(取决于操作系统和线程实现),但不能保证。

如果您尝试实现自己的线程库,理想情况下您要做的是为每个线程的堆栈分配大量地址空间,并设置 VM 系统以按需分配该空间中的内存,并在空间已满。这是大多数操作系统级线程库(如 pthread 或 win32 线程)所做的,但 VM 管理的细节很棘手。

如果你不想弄乱VM的东西,你可以为每个线程堆栈分配一个比你认为你需要的更大的堆块,然后可选地探测代码中的堆栈指针以查看它是否关闭到满(使用比您认为需要的更多的空间),如果是这样,则陷阱/中止。根据您的编译器,可能有一个选项可以让它在您可以使用的每个函数中自动生成堆栈溢出检查。

维基百科页面上的代码非常有技巧——它可能有效,但没有进行任何检查以确保有足够的堆栈空间,并且取决于编译器不会对未定义的行为做一些奇怪的事情,这会搞砸事情(例如优化掉未使用的 stack pad space,即使在分配时也可能这样做)。

于 2013-07-02T18:57:42.720 回答
0

通过堆栈操作进行任务切换通常相当容易,但 setjmp/longjmp 不足以实现此目的,除非您可以操作 jmp_buff 的内部结构。当代码退出执行 setjmp 的上下文时,由此创建的 jmp_buff 变得无效,并且任何对其执行任何操作的尝试都将导致未定义行为,即使您希望没有任何东西干扰堆栈区域,这也是正确的。执行了 setjmp。

研究您正在使用的处理器的 ABI(应用程序二进制接口)规则,并学习足够的汇编语言来执行一些基本的寄存器操作。您可能不需要超过 1-2 打的汇编代码,但您很可能需要一些。如果您使用任何类型的异常处理框架,那将尤其如此。

于 2013-07-02T17:55:13.403 回答