【问题标题】:Using MFC, posting variable to thread along with message使用 MFC,将变量与消息一起发布到线程
【发布时间】: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* 之间转换?为什么,我该怎么做?谢谢各位

【问题讨论】:

    标签: c++ multithreading casting mfc


    【解决方案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> 是哪一个?
    猜你喜欢
    • 2011-12-13
    • 1970-01-01
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 2011-11-18
    • 2021-02-26
    相关资源
    最近更新 更多