简体   繁体   中英

Occassional thread sync fail after MFC ResumeThread and std::condition_variable wait

Background I am finishing up upgrading my MFC framework project from prototype to alpha production code. The task was to synchronize its threads. I used a mixture of mutexes, condition variables and binary semaphores. This has been mostly successful. The stackoverflow case that most resembles my question is std::condition_variable wait() and notify_one() synchronization .

Problem Occasionally, though, an atomicity problem occurs after new'ing a certain class derived from CWinThread (RxWs2SocketThread). RxWs2SocketThread switches to the new class'es thread and executes InitInstance and switches back again like it is supposed to. In single-threaded programs, when ResumeThread is called, the thread switch to InitInstance occurs without problem, but in my multithreaded program, I have to control the switching. Here is the code:

线程创建和实例化代码

The occasional fail occurs between line 95 and 102. Here is the app log showing a successful handoff:

成功条件 var 在 ResumeThread 之后等待

The number to the left is the thread number. Line numbers are in brackets like [100]. Note that [100] is the instrumentation for the actual wait call on line 102. And this app log shows an example of where it fails:

条件变量等待不成功

In this log, the notify_one occurs before the wait , which causes the program to hang. Note that line [100] in the app log, which represents the wait call in the code on line [102].

Question This tells me I need to provide atomicity between the ResumeThread and std::condition_variable.wait() calls. How can I do that? I have to resume the class thread, otherwise the InitInstance won't be called, but I can't do a wait after I resume the thread.

It turns out the answer was right in front of me. On code line 101, a lock is acquired on rxWs2SocketInitInstanceMu mutex. All I had to do was move the lock up to just before line 95 ResumeThread .

Edit1: I switched out the std::condition_varialble synchronization primitive for future/promise . The former requires the use of separate locking, which does work when the locking statement is put before the ResumeThread , but this leads to error-prone maintenance. The future/promise primitive is designed to be one-off which is how it is used in my code.

Note that the std::promise object is meant to be used only once (See cppreference)

.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM