You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PostThreadMessage()传递的数据结构,多接收线程的访问是否序列化?

PostThreadMessage多线程访问共享数据的序列化问题

结论先行

你当前的写法完全没法保证两个接收线程对generic_data的访问是序列化的,甚至会直接引发数据竞争问题,必须额外添加同步机制才行。

问题出在哪

  1. PostThreadMessage的投递逻辑:这个API是把消息分别扔进线程A和线程B各自的消息队列,两个线程的GetMessage是独立读取自己队列内的消息,系统调度它们的执行时机没有任何关联——线程A可能刚拿到指针开始修改数据,线程B同时也拿到指针开始读写,结果必然导致数据错乱。
  2. 指针传递的风险:你传递的是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:03:09