线程共享地址空间,但不共享堆栈:矛盾吗?

use*_*306 6 c multithreading process

我知道线程共享地址空间,但不共享它们的堆栈。这不是自相矛盾吗?为什么说他们共享地址空间是真的,而实际上他们不共享他们的堆栈 - 堆栈是地址空间的一部分,不是吗?

我认为它线程共享堆、数据和代码段而不是堆栈段。对我来说,它们都被认为是进程地址空间。

有人可以澄清吗?谢谢!!

dbu*_*ush 6

是的,线程具有相同的地址空间但不共享堆栈。一个线程在内存中看到的任何内容,另一个线程都可以看到并且位于相同的地址,但是每个线程的堆栈位于地址空间中的不同位置,因此它们各自独立地调用其他函数而不会相互干扰。

以下面的程序为例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

void *foo(void *arg)
{
    int *n = arg;
    printf("in thread, arg=%p, value=%d, &n=%p\n", arg, *n, (void *)&n);
    return NULL;
}

int main()
{
    int x = 4;
    printf("in main, x=%d, &x=%p\n", x, (void *)&x);
    pthread_t tid;
    pthread_create(&tid, NULL, foo, &x);
    sleep(3);
    pthread_join(tid, NULL);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

main 函数将位于主线程堆栈上的局部变量的地址传递给另一个线程。该线程能够取消对该指针的引用并读取该变量的值。

在我的系统上,它输出以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

void *foo(void *arg)
{
    int *n = arg;
    printf("in thread, arg=%p, value=%d, &n=%p\n", arg, *n, (void *)&n);
    return NULL;
}

int main()
{
    int x = 4;
    printf("in main, x=%d, &x=%p\n", x, (void *)&x);
    pthread_t tid;
    pthread_create(&tid, NULL, foo, &x);
    sleep(3);
    pthread_join(tid, NULL);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这里您可以看到主线程和子线程x在主函数中看到相同的地址和值。您还可以看到,子线程堆栈中的变量ninfoo的地址与xin的地址相距很远main(大约相距 637GB)。

这表明两个线程可以使用相同的地址读取相同的内存,并且每个线程都有自己的堆栈。


use*_*723 0

旧教科书经常这样描述它们,但现代操作系统上的线程堆栈并不是进程地址空间的一些“特殊”组件。它们是内存映射,就像任何其他映射一样,由mmap.

\n\n

原始线程\xe2\x80\x94进程\xe2\x80\x94中的第一个线程可以以特殊方式获取它的堆栈,但其余线程通常由用户空间线程库(通常通过调用)分配它mmap。堆栈通常可以由用户空间操作,有时甚至可以完全替换为另一个内存分配。

\n\n

大多数操作系统甚至不检查,该线程实际上使用了一个它声称使用 \xe2\x80\x94 的堆栈,这里是最近实现的安全缓解技术的描述,该技术实现了此类检查以防御漏洞利用。

\n