die++
и die--
не являются потокобезопасными.
Внутренне это многоступенчатые операции ... чтение, увеличение / уменьшение, запись.
Если выполняются два потока одна и та же операция в одно и то же время, они, вероятно, будут неправильно считать.
Скажем, d ie находится на 5
. Потоки 1 и 2 оба пытаются выполнить die--
одновременно.
- Поток 1 читает
die
как 5 - Поток 2 читает
die
как 5 - Обновления потока 1
die
до 4 - Обновления потока 2
die
до 4 (снова)
Classi c состояние гонки.
Это гораздо менее вероятно, что это произойдет в режиме DEBUG (но не невозможно), поскольку там больше проверок потоков и больше накладных расходов в целом, а это означает, что у вас гораздо меньше шансов, что два потока будут выполнять одну и ту же команду одновременно.
Вы следует использовать Interlocked.Increment(ref die)
и Interlocked.Decrement(ref die)
Они будут добавлять / вычитать 1 поточно-ориентированным способом.
Другая потенциальная проблема ...
Ваш die
переменная не объявлена volatile
.
Это определенно будет различие со сборками DEBUG
Очень упрощенно, это означает, что переменная может быть изменена несколькими потоками, и поэтому каждый из них должен быть повторно получить «реальное» значение, а не полагаться на локальный кеш.
Это все поэтому ограничивает оптимизацию, которая может быть добавлена компилятором (в однопоточной работе компилятор может переупорядочивать операторы для оптимизации эффективности процессора, если они не влияют на результат. Это может быть намного сложнее угадать в многопоточных приложениях, и компилятор часто ошибается).
Это немного сложнее, чем это, но в результате вам нужно его использовать
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/volatile