InterlockedIncrement против EnterCriticalSection / counter ++ / LeaveCriticalSection - PullRequest
5 голосов
/ 06 декабря 2011

У меня есть многопоточный код (см. Вопрос Простой пример пула потоков Windows API ), для которого я использую счетчик для идентификации потока.

Мне посоветовали использовать InterlockedIncrement для увеличения этого счетчика в функции обратного вызова потока. Однако, похоже, это не правильно блокирует переменную, так как я столкнулся с некоторыми проблемами параллелизма. Я заменил InterlockedIncrement, используя критический раздел вручную: EnterCriticalSection / counter ++ / LeaveCriticalSection, и теперь это работает отлично.

Почему это так? Разве эти два варианта не должны быть строго эквивалентными? Обратите внимание, что я говорю о запуске только пары (около 10) потоков.

1 Ответ

27 голосов
/ 06 декабря 2011

Ваш код не использует InterlockedIncrement правильно.

InterlockedIncrement(&(thread.threadCount)); 
DWORD tid = (thread.threadCount-1)%thread.size(); 

При этом выполняется атомарный прирост 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(); 

Уникальный увеличенныйзначение возвращается InterlockedIncrement.Вам нужно использовать это значение в своих вычислениях, если вы хотите увидеть уникальное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...