将(同步)堆栈分配的内存传递给其他线程是否安全?

时间:2010-02-11 02:13:19

标签: c++ windows-mobile memory-management dynamic-memory-allocation

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

我通常会这样做:

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
}

这样做可以吗?

5 个答案:

答案 0 :(得分:3)

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

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

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

答案 1 :(得分:2)

是的,没关系。

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

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

正如其他人已经说过的那样,你如何编写它就好了,一般来说,只要一切都是同步的,只要将指向堆栈中对象的指针传递给另一个线程,就不会立即失败。但是,当这样做时,我倾向于畏缩一点,因为当发生异常或者其中一个线程涉及异步IO回调时,看似线程安全的东西可能会超出预期的顺序。如果在调用SendMessage期间其他线程中出现异常,则可能会立即返回0。如果稍后在另一个线程中处理该异常,则可能存在访问冲突。另一个潜在的危险是存储在堆栈上的任何东西永远不会被强制从另一个线程中处理掉。如果它等待一些回调,对象等永远停滞不前并且用户决定取消或退出应用程序,则工作线程无法确定停滞的线程已整理其堆栈中的任何对象。

我的观点是:在简单的场景中,你已经描述了一切都能完美运行,没有任何变化,没有外部依赖失败,共享指向本地堆栈的指针是安全的 - 但是因为在堆上分配实际上就像简单,它让你有机会在情有可原的情况下从任何线程显式控制对象的生命周期,为什么不只是使用堆?

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