4

最近听说栈中的内存不与其他线程共享,堆中的内存与其他线程共享。

我通常这样做:

HWND otherThreadHwnd;
DWORD commandId;
// initialize commandId and otherThreadHwnd

struct MyData {
  int data1_;
  long data2_;
  void* chunk_;
};

int abc() {
  MyData myData;
  // initialize myData
  SendMessage(otherThreadHwnd,commandId,&myData);
  // read myData
}

这样做可以吗?

4

5 回答 5

3

是的,在这种情况下是安全的。

堆栈上的数据仅在函数调用的生命周期内存在。由于 SendMessage 是一个同步的阻塞调用,因此数据将在该调用期间有效。

如果您将 SendMessage 替换为对 PostMessage、SendNotifyMessage 或 SendMessageCallback 的调用,则此代码将被破坏,因为它们不会阻塞,并且该函数可能在目标窗口收到消息之前已返回。

于 2010-02-11T02:15:56.637 回答
2

是的,没关系。

SendMessage正在阻塞模式下工作。即使myData在堆栈中分配,它的地址仍然对进程中的所有线程可见。每个线程都有自己的私有栈;但是堆栈中的数据可以显式共享,例如,由您的代码共享。但是,正如您猜测的那样,不要PostThreadMessage在这种情况下使用。

于 2010-02-11T02:16:41.810 回答
2

我认为无论您“听说堆栈中的内存不与其他线程共享”的人都会混淆两个不同的问题:

  1. 对象生命周期 - 堆栈上的数据仅在线程不离开变量名称范围时才有效。在您给出的示例中,您通过同步调用另一个线程来处理此问题。

  2. 内存地址可见性 - 进程的地址 pspace 在该进程中的各个线程之间共享。因此,一个线程可寻址的变量可由该进程中的其他线程寻址。如果您将地址传递给不同进程中的线程,情况就完全不同了,您需要使用一些其他机制(这可能是为了确保内存块映射到两个进程中 - 但我不这样做' t认为这通常可以用堆栈内存来完成)。

于 2010-02-11T02:27:13.453 回答
0

您听说的是“潜在侵犯隐私”,即与另一个线程共享一个线程私有堆栈上的数据。

尽管不鼓励这样做,但这只是一个“潜在的”问题——只要同步正确,就可以安全地完成。在您的情况下,此同步是由 ::SendMessage(); 完成的。直到消息在另一个线程中处理后才会返回,因此数据不会超出主线程堆栈的范围。但请注意,无论您在工作线程中使用此指针做什么,都必须在从消息处理程序返回之前完成(如果您将其存储在某处,请务必制作副本)。

于 2010-07-02T08:19:05.080 回答
0

正如其他人已经说过的那样,您如何编写它就很好,而且通常,只要一切都同步,将指向堆栈上对象的指针传递给另一个线程时,什么都不会立即失败。但是,这样做时我会有点畏缩,因为当异常发生或其中一个线程涉及异步 IO 回调时,看起来线程安全的事情可能会超出预期的顺序。如果在您调用 SendMessage 期间其他线程出现异常,它可能会立即返回 0。如果稍后在另一个线程中处理异常,您可能会遇到访问冲突。另一个潜在的危险是,存储在堆栈中的任何内容都不能从另一个线程中强制处理掉。如果它在等待一些回调、对象等时被卡住,

我的观点是:在您所描述的简单场景中,一切都运行良好,没有任何变化,并且没有外部依赖项失败,共享指向本地堆栈的指针是安全的 - 但由于在堆上分配实际上同样简单,并且它使您有机会在情有可原的情况下从任何线程显式控制对象的生命周期,为什么不直接使用堆呢?

最后,我强烈建议您对 MyData 结构的 void* chunk_ 成员非常小心,因为如果它被复制到另一个线程中,则它不是线程安全的。

于 2011-09-15T09:14:33.337 回答