动机
我试图通过保存各种环境,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
一开始有点难看,但由于数字很大,你可以只关注最后三位数字。
第一个数组从760到760——很好,它是 i = 0
第二个数组从744到754——很好,我们移动了一点,但它是一个大小为 10 的数组,处于我们想要的一般位置
第三个数组从720到740 —— 呃,哦,这个数组的起始点与其他数组不同,它的大小是原来的两倍。
为了说明堆栈上的模式,每个 * 代表一个数组中的 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?