我目前正在实现一个使用多线程但对总内存消耗有要求的应用程序。我想要一个主线程做I / O和几个工作进行计算。
目前我在工作人员访问的主堆栈上有几个数据结构。我使用OpenMP进行工作分发。由于主/工作模式与OpenMP不兼容,我想使用pthread进行多线程处理。
我知道每个线程都维护一个本地堆栈,但是在创建线程时堆栈究竟会发生什么?
工作人员是否可以访问主堆栈上的数据结构,还是应该将它们移动到堆中? 我还想避免重复数据,但不知道新线程是否会创建主堆栈的本地副本。
编辑:我自己找到答案......
在阅读了pthreads使用的clone()系统调用的细节后,我意识到所有线程共享完整的虚拟内存。这意味着虽然线程使用自己的堆栈,但仍然可以共享用于每个堆栈的内存区域。
我写了一些代码来验证这种行为:
#include <stdio.h>
#include <pthread.h>
void* increment(void* value) {
int* val = (int*) value;
for(int i = 0; i < 100; i++) {
++(*val);
}
return 0;
}
int main(int argc, char** argv) {
int stackvar = 0;
pthread_t thread1, thread2;
int iret1, iret2;
iret1 = pthread_create( &thread1, NULL, increment, (void*) &stackvar );
iret2 = pthread_create( &thread2, NULL, increment, (void*) &stackvar );
pthread_join( thread1, NULL );
pthread_join( thread2, NULL );
printf("%i\n", stackvar);
return 0;
}
当输出为“200”时,线程成功地操纵了其父线程的堆栈。
我认为互联网上的大多数资源都没有正确表达这一事实。 线程做在共享内存的意义上共享堆栈,但每个线程的堆栈指针是私有的。对于每个线程,共享内存的一部分被指定为本地堆栈。
这也意味着如果父线程在堆栈上有大型数据结构并不重要,因为内存永远不会重复进行线程化。
答案 0 :(得分:4)
是的,您可以在解释时分享您的筹码。但是,一般情况下,除少数特殊情况外,您不应该这样做。你的示例程序有数据竞争,所以输出只能通过纯粹的运气200(可能是因为你的操作系统实际上没有安排孩子同时运行。)
共享堆栈有意义的一个特殊情况是,父级创建一些有趣的数据结构,然后将其传递给子级,子级访问数据结构只读。
除了数据竞争之外,在堆栈而不是堆上共享可能会出错。父进程可以从创建子线程的过程返回,因此堆栈数据可能不会在子线程的生命周期内保持有效。因此,如果pthread_create()
调用和匹配的pthread_join()
调用位于同一范围内(例如,在示例中),则应该只共享堆栈数据。