使用 MFC,将变量与消息一起发布到线程

Posted

技术标签:

【中文标题】使用 MFC,将变量与消息一起发布到线程【英文标题】:Using MFC, posting variable to thread along with message 【发布时间】:2016-05-19 03:35:33 【问题描述】:

我正在使用CWinThread。我已经让主 GUI 向线程发送LPARAM 中的数组。例如,这段代码WORKS

//On GUI
char *headData = "L1";
PostThreadMessage(threadID,SEND_HEAD, 0, (LPARAM)head);

关于线程:

void CMyThread::OnSendhead( WPARAM, LPARAM lParam)
   char *head = (char*)lParam;
   if (strcmp(head,"L1")==0)
       //This line is reached.
   
   return;

但是当我在这里做一点改变时:

char *head = "L1"
unsigned char byteHead[3];
memcpy(byteHead, head, 3);
PostThreadMessage(threadID,SEND_HEAD, 0, (LPARAM)byteHead);

关于线程:

 void CMyThread::OnSendhead( WPARAM, LPARAM lParam)
   unsigned char* byteHead = (unsigned char*)lParam;
   char head[3];
   memcpy(head, byteHead,3);
   head[3] = '\0';
   if (strcmp(head,"L1")==0)
       //This line is nerver reached.
   
   return;

if 里面的行没有到达。我已将线程上的代码移至 GUI 进行测试(无需转换为 LPARAM),一切正常。所以我想我不能在lParamunsigned char* 之间转换?为什么,我该怎么做?谢谢各位

【问题讨论】:

【参考方案1】:

PostMessage 不会立即处理该消息,而是将其留给消息循环稍后接收。如果lparam指向的数据在这期间已经被销毁了,那就失败了。

在您的第一个示例中,您传递了一个字符串文字。字符串文字往往在程序的整个生命周期内保持有效,所以这没关系。

在第二个示例中,您使用的局部变量可能会在您执行 PostMessage 后不久被销毁。

要完成这项工作,请改用SendMessage;它会立即得到处理。或者使用保证在消息被处理之前有效的变量。

【讨论】:

所以,既然我想将消息发送到线程,我没有办法使用SendMessage,因为我必须有线程ID才能知道消息将发送到哪里。但是对于变量,我在某处读到关于让线程触摸 GUI 的成员不是一个好习惯? @TrungNguyen 我对多线程 Windows 程序没有任何经验,这是一个充满地雷的区域,到目前为止我已经成功地避开了它。除了答案之外,我真的无法给你任何可靠的建议。 谢谢您,您的回答是正确的,在线程拾取消息之前,变量已被淘汰。我使用 memcpy 将值存储到另一个变量,它可以工作。【参考方案2】:

对于PostMessagePostThreadMessage,您应该始终使用堆分配内存来发送数据,小到bool,然后在消息处理函数中删除它。你可以用一些struct包裹一条消息,例如:

 struct MyMsg
    
       int msgCode; // specific to you, and you know underlying datatype
       char buffer[1024]; // or have a `vector` or dynamic-array you'd manage
    ;

发件人:

MyMsg* msg = new MyMsg;
msg->msgCode = 0x1; // It's a string
strcpy_s(msg->buffer, "abc");
PostThreadMessage(threadID,SEND_HEAD, 0, (LPARAM)msg);

接收者

void CMyThread::OnSendhead( WPARAM, LPARAM lParam)

    MyMsg* msg= (MyMsg*)lParam;
    // use msg
    delete msg;

【讨论】:

谢谢你,很好地使用了结构。但是,如果发件人中的msg 没有被删除,这是否是内存泄漏? 没有。接收器正在删除内存。这是一个单一的过程。同一进程的所有线程完全共享内存。由于两个线程有​​不同的调用堆栈,你不能将一个堆栈内存共享给另一个线程(除非你使用阻塞调用,例如SendMessage)。您可以在接收器中使用一些智能指针来确保删除内存。您可能还有内存池,以便可以减少内存分配/取消分配,用于发送方-接收方通信。还有很长的路要走... ;) 没有必要在freestore上分配任何可以按值传递的东西。而且freestore并不是延长数据生命周期的唯一方法(对象生命周期才是真正重要的,而不是它的存储位置)。具有静态存储持续时间的对象将是另一种方式。此外,发布到线程的消息可能会丢失(因此您确实存在潜在的内存泄漏)。这甚至没有涉及跨模块边界传递 CRT 资源的问题。非常危险的建议,值得一票。 对于小型类型,是的,它们不需要堆分配。但是对于字符串等消息,它是必需的。 PostMessage 调用本身会失败,并且发送者可以删除内存 - 如果 PM 调用成功,它不会失败。我们需要为多个 CRT 版本派生技术(比如一个分配/释放内存的类,该类驻留在一个 DLL 中)。这并不危险。你对我的建议有意见,我帮不上什么忙。 PostMessage 不会向线程发布消息。 PostThreadMessage 确实(并且消息可以静默丢弃)。你需要下定决心:“使用堆分配的内存来发送数据,小到bool” - “对于小类型,是的,它们不需要堆分配。” i> 是哪一个?

以上是关于使用 MFC,将变量与消息一起发布到线程的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows C++ 应用程序中控制主线程

mfc 关于Accept函数

工作线程中的同步与异步 ioctl

工作线程没有消息循环(MFC、windows)。我们可以让它接收消息吗?

C++ - 将 Hunspell 与 MFC 一起使用

MFC 应用程序在事件泛滥时做出响应