MFC工作线程同步问题:多线程访问configDone变量异常处理
MFC多线程configDone变量同步问题解决方案
你的问题核心有两个:一是共享变量的内存可见性(工作线程可能缓存了configDone的旧值),二是循环迭代的执行时序(主线程修改状态时,工作线程已经进入旧分支的执行逻辑)。以下是具体解决方法:
1. 用临界区保护共享变量的读写
多线程环境下,所有访问共享变量configDone的操作(包括主线程修改、工作线程判断)都需要加锁,确保读写操作的原子性和内存可见性,避免竞态问题。
修改步骤:
- 在
myClass中添加临界区成员:
class myClass { private: CCriticalSection m_csConfig; // 保护configDone的临界区 public: tComSts configDone; // 其他成员... };
- 工作线程读取
configDone时加锁:
UINT WorkerThread::ThreadFunction(LPVOID pParam) { myClass *myMaster = reinterpret_cast<myClass *>(pParam); if (nullptr != myMaster) { while (true) { tComSts currentSts; // 加锁读取当前状态,确保拿到最新值 { CSingleLock lock(&myMaster->m_csConfig, TRUE); currentSts = myMaster->configDone; } if (tComSts::COM_CFG_DONE == currentSts) { st_msg rmsg = {0}; myMaster->ReceiveResponse(true, TIMEOUT_RECEIVE, &rmsg); } else if (tComSts::COM_CFG_NONE == currentSts) { // do some work } else { // do nothing } // 可选:添加小延迟,降低CPU占用 Sleep(THREAD_DELAY_MS); } } return 0; }
- 主线程修改
configDone时同样加锁:
// 主线程修改状态的代码 { CSingleLock lock(&myMaster->m_csConfig, TRUE); myMaster->configDone = tComSts::XXX; }
2. 声明configDone为volatile(解决内存可见性)
如果暂时不想用锁,至少要将configDone声明为volatile,禁止编译器对变量做缓存优化,确保工作线程每次都从内存读取最新值:
class myClass { public: volatile tComSts configDone; // 加volatile关键字 // 其他成员... };
注意:volatile仅保证可见性,无法解决「判断后状态被修改」的竞态问题(比如工作线程判断为COM_CFG_DONE后,主线程立刻修改状态,但工作线程已进入ReceiveResponse执行),因此更推荐和临界区配合使用。
3. 用事件对象实现线程即时响应
当前工作线程是死循环轮询,即使状态改变,也要等当前迭代完成才能响应。可以用MFC的CEvent让主线程主动通知工作线程状态变化,减少空转并提升响应速度:
修改步骤:
- 在
myClass中添加事件成员:
class myClass { private: CCriticalSection m_csConfig; CEvent m_eventConfigChanged; // 状态变化通知事件 public: volatile tComSts configDone; // 其他成员... };
- 工作线程中等待事件,状态变化时立即唤醒:
UINT WorkerThread::ThreadFunction(LPVOID pParam) { myClass *myMaster = reinterpret_cast<myClass *>(pParam); if (nullptr != myMaster) { while (true) { tComSts currentSts; { CSingleLock lock(&myMaster->m_csConfig, TRUE); currentSts = myMaster->configDone; } if (tComSts::COM_CFG_DONE == currentSts) { st_msg rmsg = {0}; myMaster->ReceiveResponse(true, TIMEOUT_RECEIVE, &rmsg); } else if (tComSts::COM_CFG_NONE == currentSts) { // do some work } else { // do nothing } // 等待状态变化事件,超时时间保留轮询间隔 DWORD waitResult = myMaster->m_eventConfigChanged.WaitForObject(THREAD_DELAY_MS); if (waitResult == WAIT_OBJECT_0) { // 事件触发后重置,等待下一次通知 myMaster->m_eventConfigChanged.ResetEvent(); } } } return 0; }
- 主线程修改状态后触发事件:
{ CSingleLock lock(&myMaster->m_csConfig, TRUE); myMaster->configDone = tComSts::XXX; } // 通知工作线程状态已变 myMaster->m_eventConfigChanged.SetEvent();
这样工作线程在状态变化时会被立即唤醒,无需等到轮询周期结束,响应效率更高。
内容的提问来源于stack exchange,提问作者DEVTOIMPROVE
相关产品推荐
相关产品推荐

