用于线程的循环中的C数组分配

时间:2013-02-22 16:21:50

标签: c arrays optimization compiler-construction

动机

我试图通过setjmp保存各种环境,以便稍后跳回到它们并调用函数并确保堆栈帧相互碰撞。例如:

env [0] stack:

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

其中波浪号代表主等的堆栈帧。

env [1] stack:

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

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

我的想法是,如果我longjmpenv[0]并开始运行某些方法,然后longjmpenv[1]并开始运行一些方法,那么env[0]的堆栈帧1}}将开始填充该数组中的空白空间,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数组吗?

我如何获得测试2和3的分配,测试1的大小?

1 个答案:

答案 0 :(得分: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]
}