如何使用postThreadMessage传递结构体

5
我想使用Windows的消息队列功能将一个结构体发送到另一个线程。但我发现postthreadmessage函数只提供了两个整数参数lparam和wparam来传递参数。所以我决定将结构体的地址放在lparam中。这是Windows用于传递结构体的正确方式吗?
我打算使用boost::shared_ptr在接收线程和发送线程中持有结构体的地址。我怀疑当这两个shared_ptrs超出范围时,结构体会被释放两次吗?我无法想出一种确保堆上分配的结构体被100%释放的方法,有什么建议吗?

1
是的,当然。比较WM_COPYDATA。只需让接收方释放内存即可。如果接收线程显示任何窗口,甚至是消息框,都不要使用PostThreadMessage()。 - Hans Passant
1
@Hans Passant老帖子了,但您能简要解释一下为什么在这种情况下使用PostThreadMessage()是不好的吗?可能会有什么后果? - Mark Ch
2个回答

0
对于第一个问题,是的,LPARAM旨在被用作整数或指针。这一点从定义中可以清楚地看出:
typedef LONG_PTR LPARAM;

这是一个足够长的整数来保存一个指针。

关于shared_ptr的事情,你是对的,如果传递原始指针并将其包装到另一个shared_ptr中,则会释放两次:

shared_ptr<Thing> a;
PostThreadMessage(x, 0, (LPARAM)a.get());
...
LRESULT OnMessage(int msg, WPARAM wp, LPARAM lp)
{
    shared_ptr<Thing> p((Thing*)lp); //Bad!!!
}

但是你可以尝试这个解决方法:

shared_ptr<Thing> a;
PostThreadMessage(x, 0, new shared_ptr<Thing>(a)); //pointer to smart-pointer
...
LRESULT OnMessage(int msg, WPARAM wp, LPARAM lp)
{
    shared_ptr<Thing> *pp = (shared_ptr<Thing>*)lp;
    shared_ptr<Thing> p(*pp);
    delete pp; //no leak
}

顺便提一下:请注意,PostThreadMessage可能会失败...而且您不想泄漏shared_ptr。

根据我的经验,通常最好使用std::deque来保存数据,并使用PostThreadMessage来通知有数据存在。这样,您永远不会丢失对象!但是,您的情况可能有所不同。


是的,但是使用共享数据需要显式的线程同步,并且会阻塞。我之所以使用消息是因为我想要异步写入,并且不需要显式的锁操作。我想我可以在写入线程中分配内存,在读取线程中释放它,希望PostThreadMessage永远不会失败... - Jason
注释后的想法:使用指向“weak_ptr”的指针如何?泄漏“weak_ptr”要比泄漏“shared_ptr”好得多,只要消息发送方持有“shared_ptr a”,当接收方需要时对象仍将存在。 - Rasmus Storjohann
1
我只看过PostThreadMessage失败了两种情况:a) 目标队列已满(我数了大约40000条消息,但极限未记录,因此可能取决于许多参数);b) 目标线程尚未创建消息队列。该队列将在线程首次使用函数访问它(例如 GetMessage)时自动创建。因此,如果您创建线程并立即调用 PostThreadMessage 它可能会失败。为确保安全,请检查返回值:如果PostThreadMessage失败,则返回FALSE。 - rodrigo

0

我曾经遇到过类似的情况,使用Qt的QModelIndex类来保存数据,它使用void*类型,但是我使用shared_ptr来管理它指向的数据。

为了避免直接解引用void*,因为它可能指向一个不存在的对象,我使用一个从void*weak_ptr的映射。所有被QModelIndexes引用的对象都存储在这个映射中。当需要解引用void*时,我使用void*作为键从映射中检索相应的weak_ptr,然后将weak_ptr转换为shared_ptr。这个shared_ptr要么等于void*,要么为NULL,这样你也能获得类型安全。

请注意,我的解决方案不必处理您提到的并发问题,但您可能能够将其适应于您的情况。您可以使用lparam存储指向您对象的原始指针,然后使用map从原始指针转换为智能指针。使用互斥锁来保护地图,那么您就可以了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接