18

正如标题所说,两个或多个线程如何共享它们分配的堆上的内存?我一直在考虑,但我不知道他们是如何做到的。这是我对过程的理解,想必我在某个地方错了。

任何线程都可以通过进行系统调用来添加或删除堆上给定数量的字节,该系统调用返回指向该数据的指针,大概是通过写入寄存器,然后线程可以将其复制到堆栈中。所以两个线程 A 和 B 可以根据需要分配尽可能多的内存。但是我看不到线程 A 怎么知道线程 B 分配的内存在哪里。我也不知道任何一个线程如何知道另一个线程的堆栈所在的位置。多线程程序共享堆,我相信,可以访问彼此的堆栈,但我不知道如何。

我尝试搜索这个问题,但只找到了抽象出细节的语言特定版本。

编辑:我试图不特定于语言或操作系统,但我使用的是 Linux,并且从低级别的角度来看它,我猜是汇编。

4

5 回答 5

13

我对您的问题的解释:线程 A 如何知道指向 B 正在使用的内存的指针?他们如何交换数据?

答:它们通常以指向公共内存区域的公共指针开始。这允许它们相互交换其他数据,包括指向其他​​数据的指针。

例子:

  1. 主线程分配一些共享内存并将其位置存储在p
  2. 主线程启动两个工作线程,将指针传递p给它们
  3. 工作人员现在可以使用p和处理p

在真正的语言 (C#) 中,它看起来像这样:

//start function ThreadProc and pass someData to it
new Thread(ThreadProc).Start(someData)

线程通常不访问彼此的堆栈。一切都从传递给线程过程的一个指针开始。


创建线程是一项操作系统功能。它是这样工作的:

  1. 应用程序使用标准 ABI/API 调用操作系统
  2. 操作系统分配堆栈内存和内部数据结构
  3. 操作系统“伪造”第一个堆栈帧:它将指令指针设置为 ThreadProc 并将 someData “推入”堆栈。我说“伪造”是因为第一个堆栈帧不是自然产生的,而是由操作系统人为创建的。
  4. 操作系统调度线程。ThreadProc 不知道它已在新堆栈上设置。它所知道的是 someData 位于它所期望的通常堆栈位置。

这就是 someData 到达 ThreadProc 的方式。这是第一个初始数据项的共享方式。步骤 1-3 由父线程同步执行。4发生在子线程上。

于 2012-08-10T22:04:22.357 回答
2

从鸟瞰的角度来看一个非常简短的答案(1000 英里以上):
线程是同一进程的执行路径,而堆实际上属于该进程(并且因此由线程共享)。每个线程只需要它自己的堆栈作为一个单独的工作单元。

于 2012-08-10T21:12:44.627 回答
0

如果线程都使用相同的堆,则它们可以共享堆上的内存。默认情况下,大多数语言/框架都有一个默认堆,代码可以使用该堆从堆中分配内存。在非托管语言中,您通常会显式调用分配堆内存。例如,在 C 中,可能是malloc等。在托管语言中,堆分配通常是自动的,分配的方式取决于语言——通常是通过使用new运算符。但是,这稍微取决于上下文。如果您提供您要询问的操作系统或语言环境,我也许可以提供更多详细信息。

于 2012-08-10T21:51:37.797 回答
0

与属于同一进程的其他线程共享的线程:它的代码段、数据段和其他操作系统资源,例如打开的文件和信号。

于 2015-05-10T08:47:03.970 回答
0

您缺少的部分是包含静态变量的静态内存

该内存在程序启动时分配,并分配已知地址(在链接时确定)。所有线程都可以在不交换任何数据运行时访问此内存,因为地址被有效地硬编码。

一个简单的示例可能如下所示:

// Global variable.
std::atomic<int> common_var;

void thread1() {
  common_var = compute_some_value();
}

void thread2() {
  do_something();
  int current_value = common_var;
  do_more();
}

当然,全局值可能是一个指针,可以用来交换堆内存。生产者分配一些对象,消费者获取并使用它们。

// Global variable.
std::atomic<bool> produced;
SomeData* data_pointer;

void producer_thread() {
  while (true) {
    if (!produced) {
      SomeData* new_data = new SomeData();
      data_pointer = new_data;
      // Let the other thread know there is something to read.
      produced = true;
    }
  }
}

void consumer_thread() {
  while (true) {
    if (produced) {
      SomeData* my_data = data_pointer;
      data_pointer = nullptr;
      // Let the other thread know we took the data.
      produced = false;
      do_something_with(my_data);
      delete my_data;
    }
  }
}

请注意:这些不是良好的并发代码示例,但它们显示了总体思路,没有太多混乱。

于 2020-11-09T16:29:05.637 回答