InterlockedIncrement vs EnterCriticalSection/counter ++/LeaveCriticalSection

nbo*_*eel 5 c++ windows multithreading thread-safety

我有一些多线程代码(请参阅问题Windows API线程池简单示例),我正在使用计数器来识别线程.

我被建议使用InterlockedIncrement在线程的回调函数中递增此计数器.然而,这似乎没有正确锁定变量,因为我遇到了一些并发问题.我通过手动使用临界区替换了InterlockedIncrement:EnterCriticalSection/counter ++/LeaveCriticalSection,现在可以完美地运行.

为什么会这样?这两个选项不应该严格等同吗?请注意,我正在谈论启动一对(大约10个)线程.

Ray*_*hen 27

您的代码未InterlockedIncrement正确使用.

InterlockedIncrement(&(thread.threadCount)); 
DWORD tid = (thread.threadCount-1)%thread.size(); 
Run Code Online (Sandbox Code Playgroud)

这将执行原子增量thread.threadCount,但不是保存原子递增的值,而是忽略它并返回到thread.threadCount变量(在此期间可能已经被另一个线程增加).

在你的情况下,会发生的事情是两个线程InterlockedIncrement几乎同时进行,将它从1增加到2,然后增加到2到3.然后两个线程都读取thread.threadCount并返回3(然后减去1得到最终结果为2).

正确的代码是

LONG tidUnique = InterlockedIncrement(&(thread.threadCount));
DWORD tid = (tidUnique-1)%thread.size(); 
Run Code Online (Sandbox Code Playgroud)

返回唯一递增的值InterlockedIncrement.如果要查看唯一值,则需要在计算中使用该值.