2

动机

我试图通过保存各种环境,setjmp以便稍后跳回它们并调用函数并确保堆栈帧彼此运行。例如:

环境 [0] 堆栈:

----------
|  text  |
----------
|  data  |
----------
|        |
|        |
|        |
|        |
|        |
|        |
|        |
|  ~~~~  |
----------

其中波浪线代表 main 等的堆栈帧。

环境 [1] 堆栈:

----------
|  text  |
----------
|  data  |
----------
|        |
|        |
|        |
|  ****  |
|  ****  |
|  ****  |
|  ****  |
|  ~~~~  |
----------

星星代表我分配的一个大数组。

这个想法是,如果我longjmp开始env[0]运行一些方法,然后longjmp开始env[1]运行一些方法,堆栈帧env[0]将开始填充该数组中的空白空间,堆栈帧env[1]将位于该数组的顶部,并且不覆盖env[0]. 基本线程。

我还想要不止两个线程,事实上,我想要 MAXTHREADS。直观地说,它是这样工作的:

for(int i = 0; i < MAXTHREADS; i++) {
    char c[STACKSIZE];
    if( setjmp(env[i]) != 0 ) {
        /* Stuff that thread i will do goes here */
    }
}

测试 1

但是,正如您在下面的测试程序中可以清楚地看到的那样,每个 c 数组都从堆栈上的同一位置开始,违背了目的。

for(int i = 0; i < 10; i++) {
    char c[10];
    printf("On Iteration %d array starts at %x and goes to %x\n",i,c,c+10);
}

输出:

On Iteration 0 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 1 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 2 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 3 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 4 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 5 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 6 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 7 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 8 array starts at ffbfef02 and goes to ffbfef0c
On Iteration 9 array starts at ffbfef02 and goes to ffbfef0c

出于多种原因,这是有道理的,范围表明 c 数组在循环结束时不再存在,另外编译器可能会将其移出循环,因为大小是静态的。

测试 1 给了我想要的大小,但不是我想要的分配

测试 2

所以我的下一个想法是分配一个 STACKSIZE * i 的数组,这样即使每个数组都从同一个位置开始,它们每次都会更大,并且在切换到那个环境时将我的堆栈指针推得足够远. 这是测试:

for(int i = 0; i < 10; i++) {
    char c[10 * i];
    printf("On Iteration %d array starts at %u and goes to %u\n",i,c,c+(10*i));
    //note: switched from %x to %u to make comparison mentally simpler
}

然而,这输出

On Iteration 0 array starts at 4290768760 and goes to 4290768760
On Iteration 1 array starts at 4290768744 and goes to 4290768754
On Iteration 2 array starts at 4290768720 and goes to 4290768740
On Iteration 3 array starts at 4290768688 and goes to 4290768718
On Iteration 4 array starts at 4290768648 and goes to 4290768688
On Iteration 5 array starts at 4290768592 and goes to 4290768642
On Iteration 6 array starts at 4290768528 and goes to 4290768588
On Iteration 7 array starts at 4290768456 and goes to 4290768526
On Iteration 8 array starts at 4290768376 and goes to 4290768456
On Iteration 9 array starts at 4290768280 and goes to 4290768370

一开始有点难看,但由于数字很大,你可以只关注最后三位数字。

第一个数组从760760——很好,它是 i = 0

第二个数组从744754——很好,我们移动了一点,但它是一个大小为 10 的数组,处于我们想要的一般位置

第三个数组从720740 —— 呃,哦,这个数组的起始点与其他数组不同,它的大小是原来的两倍。

为了说明堆栈上的模式,每个 * 代表一个数组中的 10 个字符,星块之间的间隙是数组之间的间隙:

*
*
*

*
*

*
~

波浪号是主要的,等等。

模式还在继续。这可能与机器有关,但我的机器是按顺序分配数组,而不是像固定大小的数组那样每次都回到底部。

测试 2 给了我想要的分配,但大小比我想要的要大。

测试 3

现在了解到我的机器将分配数组,如果它们的大小相同,则它们会相互覆盖,但如果它们的大小不同,则它们会堆叠在一起,我想也许我可以分配STACKSIZE + i而不是STACKSIZE * i每个。我进行了这个实验:

for(int i = 0; i < 10; i++) {
    char c[10+i];
    printf("On Iteration %d array starts at %u and goes to %u\n",i,c,c+10+i);
}

哪个输出:

On Iteration 0 array starts at 4290768808 and goes to 4290768818
On Iteration 1 array starts at 4290768792 and goes to 4290768803
On Iteration 2 array starts at 4290768776 and goes to 4290768788
On Iteration 3 array starts at 4290768760 and goes to 4290768773
On Iteration 4 array starts at 4290768744 and goes to 4290768758
On Iteration 5 array starts at 4290768728 and goes to 4290768743
On Iteration 6 array starts at 4290768712 and goes to 4290768728
On Iteration 7 array starts at 4290768688 and goes to 4290768705
On Iteration 8 array starts at 4290768664 and goes to 4290768682
On Iteration 9 array starts at 4290768640 and goes to 4290768659

经过分析,它使用了我预期的相同分配行为。

测试 3 给了我想要的分配,尺寸接近我想要的,但仍然不完美

问题

所以测试 3 的策略可以在我的原始代码中运行,分配 STACKSIZE + i 的 MAXTHREADS 数组,在每个数组之间保存 env,但它似乎不是最理想的。我在每个数组中分配额外的空间只是为了欺骗我的编译器。

有一个更好的方法吗?让编译器每次都分配新的 STACKSIZE 数组的其他技巧?

如何使用测试 1 的大小分配测试 2 和 3?

4

1 回答 1

0

你必须做这样的事情:

jmp_buf states[NUMTHREADS]
char stacks[NUMTHREADS][STACKSIZE];
// your scheduler starts *after* this!
for(;;) {
    // setjmp to remember the current thread's state
    // longjmp to thread i+1 and use stacks[i+1][top]
}
于 2013-02-22T16:26:27.793 回答