使用 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),一切正常。所以我想我不能在lParam
和unsigned char*
之间转换?为什么,我该怎么做?谢谢各位
【问题讨论】:
【参考方案1】:PostMessage
不会立即处理该消息,而是将其留给消息循环稍后接收。如果lparam
指向的数据在这期间已经被销毁了,那就失败了。
在您的第一个示例中,您传递了一个字符串文字。字符串文字往往在程序的整个生命周期内保持有效,所以这没关系。
在第二个示例中,您使用的局部变量可能会在您执行 PostMessage
后不久被销毁。
要完成这项工作,请改用SendMessage
;它会立即得到处理。或者使用保证在消息被处理之前有效的变量。
【讨论】:
所以,既然我想将消息发送到线程,我没有办法使用SendMessage
,因为我必须有线程ID才能知道消息将发送到哪里。但是对于变量,我在某处读到关于让线程触摸 GUI 的成员不是一个好习惯?
@TrungNguyen 我对多线程 Windows 程序没有任何经验,这是一个充满地雷的区域,到目前为止我已经成功地避开了它。除了答案之外,我真的无法给你任何可靠的建议。
谢谢您,您的回答是正确的,在线程拾取消息之前,变量已被淘汰。我使用 memcpy 将值存储到另一个变量,它可以工作。【参考方案2】:
对于PostMessage
或PostThreadMessage
,您应该始终使用堆分配内存来发送数据,小到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,将变量与消息一起发布到线程的主要内容,如果未能解决你的问题,请参考以下文章