为线程分配栈内存

3

我正在使用c语言中的setjmp()和longjmp()在多线程环境下编写程序。

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

我可以像这样预先分配静态空间:

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的代码片段)但这似乎过于死板,我只是想知道多线程环境通常如何为每个线程分配内存?谢谢。

通常情况下,“CreateThread”或其他调用会使用一些“kmalloc”内核函数来分配堆栈空间,并适当地预先加载它,以便线程可以通过中断返回启动,就像它之前一直在运行并被抢占一样。 - Martin James
我怀疑你已经超出了自己的能力范围。 - Hot Licks
1
这可能是真的,但任何建议都受欢迎,只是请不要在你从高马上跳下来时踩到我... - jayjay
2个回答

5
一般来说,线程分配的最大堆栈空间在创建线程时是固定的,如果线程超过了这个限制,结果是未定义的行为--无法增加堆栈空间超过该限制。如果幸运的话,堆栈溢出会导致某种堆栈溢出异常或信号(取决于操作系统和线程实现),但没有保证。
如果您想实现自己的线程库,理想情况下要做的是为每个线程的堆栈分配大量地址空间,并设置VM系统以按需在该空间中分配内存,并在空间满时陷入。这就是大多数操作系统级线程库(如pthreads或win32 threads)所做的,但VM管理的细节很棘手。
如果您不想麻烦VM的东西,可以在堆上为每个线程堆栈分配一个比您认为需要的更大的块,然后在代码中可选地探测堆栈指针,看其是否接近满(使用比您认为需要更多的空间),并在必要时陷入/中止。根据您的编译器,可能有一个选项让它在每个函数中自动生成堆栈溢出检查,您可以使用该选项。
维基百科页面上的代码非常草率--它可能起作用,但不会做任何检查以确保有足够的堆栈空间,并依赖编译器不对会破坏事情的未定义行为(如优化未使用的堆栈填充space,即使进行了分配)。

非常感谢。这很有趣,我本以为会分配可变数量的空间,但如果是这样的话... 如果有人在以后的日期遇到这个问题; 有人在这里为AVR实现了一个mt env:http://think.ow2.org/pdf/AVRMultithreading.pdf,为每个作业使用固定大小的堆栈。他们的代码可能会很有用或富有启发性。再次感谢! - jayjay

0

通过堆栈操作进行任务切换通常相当容易,但是setjmp/longjmp不是适合此目的的工具,除非您可以操纵jmp_buff的内部结构。一旦代码退出执行setjmp的上下文,由此创建的jmp_buff将变得无效,任何尝试对其进行任何操作都会导致未定义行为,即使您希望不会干扰执行setjmp的堆栈区域。

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


你说得非常正确。我意识到我陷入了“未定义行为”,但根据我所读的,大多数longjmp()的实现都会保留它们所在的作用域。即使我用汇编语言编写,我仍然会遇到相同的内存分配问题。 - jayjay
@jayjay:setjmp/longjmp 的某些实现可能有效,但除非你研究并理解它们的确切操作,否则你不会知道什么时候会出现问题;即使你研究了它们,你也不会知道未来的版本是否总是以相同的方式工作。每当我做协作式任务切换器时,我总是将所有“额外”任务的堆栈放入我专门分配的内存区域中。使用堆栈感觉不太对。 - supercat
谢谢,看起来这似乎是正确的方法,我可能会选择汇编语言路线。再次感谢您的建议! - jayjay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接