Зачем использовать System.Threading.Interlocked.Decrement вместо минуса?
Я конвертировал некоторый код на C# в vb.net, а converter.telerik.com превратил это:
i--;
в это:
System.Math.Max(System.Threading.Interlocked.Decrement(i), i + 1)
Что со всей этой фантазией?
5 ответов
Комментарий Михаила Пясковского вызвал следующее объяснение:
Семантика i--
в C# должны вернуть текущее значение i
(т. е. значение до появления декремента), а затем декремент i
одним.
Итак, нам нужно преобразовать это в VB. Мы не можем использовать i -= 1
потому что это не возвращает текущее значение i
до декремента. Итак, нам нужна операция, которая будет уменьшать i
но вернуть значение i
перед декрементом что-то вроде:
Function DoPostDecrement(ByRef i As Integer) As Integer
i -= 1
Return i + 1
End Function
Но это предполагает использование следующего, чтобы избежать необходимости писать метод для выполнения вышеизложенного:
System.Math.Max(
someValueThatIsEqualToiMinusOne,
someValueThatIsEqualtoiBeforeTheDecrement
)
Но VB.NET не позволит вам использовать i -= 1
или же i = i - 1
на месте someValueThatIsEqualToiMinusOne
, Тем не мение, System.Threading.Interlocked.Decrement(i)
законно и равно значению i - 1
, Как только вы это сделаете, потому что параметры оцениваются слева направо, someValueThatIsEqualtoiBeforeTheDecrement
должно быть i + 1
(на тот момент декремент был выполнен до i + 1
это значение перед декрементом.
Обратите внимание, что вышеуказанный метод DoPostDecrement
и System.Math.Max, System.Threading.Interlocked.Decrement
Конструкция может иметь различную семантику в многопоточном контексте.
Операция с блокировкой является атомарной; в многопоточных контекстах вы можете безопасно использовать его, не удерживая блокировку, если вы осторожны.
Это зависит от того, является ли "i" общей переменной? Это в поточно-безопасной среде?
Если "i" является целым числом, то i-- делает по существу следующее (игнорируя детали):
- вычитает один из меня
- присваивает это значение обратно мне
Как видите, есть> 1 шаг. Если "i" находится в не поточнобезопасном месте (статическая переменная совместно используется потоками и т. Д.), То поток может потенциально остановиться в середине этих двух шагов, другой поток может выполнить оба шага, и тогда у вас будет проблема с неверными данными.
Класс Interlocked по существу объединяет два вышеупомянутых шага в один шаг, обеспечивая атомарную операцию. Теперь вам не нужно беспокоиться о потоках, так как это одна операция, которая не может быть прервана другим потоком.
Чтобы ответить на ваш вопрос, выглядит так converter.telerik.com
вещь слишком консервативна в отношении проблем с многопоточностью. WAAAY чрезмерно консервативный. Я бы вернул код i--
если тот же экземпляр i
не мутирует одновременно из нескольких потоков.
Единственная причина, по которой я вижу это
Уменьшает указанную переменную и сохраняет результат как элементарную операцию.