使用PostThreadMessage()传递的数据结构,多接收线程的访问是否序列化?
PostThreadMessage多线程访问共享数据的序列化问题
结论先行
你当前的写法完全没法保证两个接收线程对generic_data的访问是序列化的,甚至会直接引发数据竞争问题,必须额外添加同步机制才行。
问题出在哪
- PostThreadMessage的投递逻辑:这个API是把消息分别扔进线程A和线程B各自的消息队列,两个线程的
GetMessage是独立读取自己队列内的消息,系统调度它们的执行时机没有任何关联——线程A可能刚拿到指针开始修改数据,线程B同时也拿到指针开始读写,结果必然导致数据错乱。 - 指针传递的风险:你传递的是
generic_data的内存地址,两个线程拿到的是同一块内存的入口,没有任何锁或同步约束的话,并发读写共享内存一定会出现不可预测的问题。
怎么实现真正的序列化访问
要让两个线程对共享数据的操作排队执行,必须添加同步锁,常用的方案有这几种:
- 临界区(Critical Section):轻量级同步方式,适合同一进程内的线程同步
- 互斥量(Mutex):支持跨进程同步,比临界区稍重
- 事件(Event):可主动控制线程执行顺序,比如让线程A处理完后再通知线程B启动
给你贴个临界区的实际用法:
首先在全局或所有线程都能访问到的位置定义临界区:
CRITICAL_SECTION g_dataLock;
程序启动时完成初始化:
InitializeCriticalSection(&g_dataLock);
然后将两个接收线程的消息处理逻辑修改为:
MSG msg; while (GetMessage(&msg, NULL, NULL, 0)) { // 进入临界区,同一时间仅允许一个线程进入 EnterCriticalSection(&g_dataLock); // 安全操作共享数据 GenericData* targetData = reinterpret_cast<GenericData*>(msg.wParam); // 此处编写你的读写逻辑,比如读取字段、修改值等 // 退出临界区,释放锁允许其他线程进入 LeaveCriticalSection(&g_dataLock); }
程序退出前别忘了销毁临界区:
DeleteCriticalSection(&g_dataLock);
额外要注意的坑
- 禁止传递局部变量的指针!如果
generic_data是某个函数内的局部变量,等线程收到消息时该变量可能已经被销毁,拿到的就是野指针,直接导致程序崩溃。 - 确保
generic_data的生命周期覆盖两个线程的处理周期,或者使用动态分配的内存(记得处理内存泄漏问题)。
内容的提问来源于stack exchange,提问作者Julien Poivret
相关产品推荐
相关产品推荐

