0

我目前打算使用 clone() 实现线程,一个问题是,如果我让所有线程使用相同的内存空间,我在给定线程中调用的每个函数,当相同的函数时,每个线程是否会使用不同的内存部分打电话,还是我必须做一些事情来确保发生这种情况?

4

1 回答 1

0

每个线程总体上将使用相同的内存映射,但为函数调用使用不同的、单独的线程本地堆栈。当不同的线程调用了同一个函数(它本身位于同一个可执行内存位置)时,任何局部变量都不会被共享,因为它们在进入函数时/根据需要分配在堆栈上,并且每个线程都有自己的默认堆栈。

对任何静态/全局内存的引用(即,未在线程本地堆栈上分配的任何内容,例如全局变量或对mmap调用后传递给线程/对线程可见的堆或内存区域的引用clone,通常是完整的内存映射和进程上下文本身)当然会被共享,并受到通常的多线程问题(即共享状态的同步)的影响。

请注意,在调用clone. 从手册页:

child_stack参数指定子进程使用的堆栈的位置。由于子进程和调用进程可能共享内存,因此子进程不可能与调用进程在同一个堆栈中执行。因此,调用进程必须为子堆栈设置内存空间,并将指向该空间的指针传递给clone(). 堆栈在所有运行 Linux 的处理器(HP PA 处理器除外)上向下增长,因此child_stack通常指向为子堆栈设置的内存空间的最高地址。

child_stack参数是 的第二个参数clone。调用者(即父线程)有责任确保通过创建的每个子线程clone为其堆栈接收一个单独且不重叠的内存块。

请注意,分配和设置这个线程本地堆栈内存区域一点也不简单。确保您的分配是页面对齐的(起始地址在 4K 边界上)、页面大小 (4K) 的倍数、足够大(如果您只有几个线程,则 2MB 是安全的),并且理想情况下包含“可用空间后面的守卫”部分。堆栈保护是一些没有访问权限的页面 - 不读取,不写入 - 在主堆栈区域之后保护虚拟内存地址空间的其余部分,如果线程动态超过其堆栈大小(例如,有一堆递归或具有非常大的临时缓冲区作为局部变量的函数)并尝试继续增长到堆栈保护区域,这将提前失败,因为线程将立即获得 SIGSEGV 而不是阴险的破坏。堆栈保护在技术上是可选的。您可能应该使用mmap分配你的堆栈,虽然posix_memalign也可以。

说了这么多,我不得不问:为什么要尝试实现线程clone?这里有一些非常具有挑战性的问题,POSIX 线程库已经解决了这些问题(也以可移植的方式)。clone如果是您想要的细粒度控制,请检查pthread_attr_*功能;它们几乎涵盖了所有非晦涩的用例(例如,如果您愿意,允许您分配自己的堆栈——从之前的讨论中,我认为您不会)。非常高性能的通用 Linux 实现,除其他外,完全包装clone和大量其他与线程相关的令人发指的系统调用——其中许多甚至没有 C 库包装器,必须通过syscall. 这一切都取决于你想做什么。

于 2012-11-22T00:15:32.180 回答