Зачем использовать 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. вычитает один из меня
  2. присваивает это значение обратно мне

Как видите, есть> 1 шаг. Если "i" находится в не поточнобезопасном месте (статическая переменная совместно используется потоками и т. Д.), То поток может потенциально остановиться в середине этих двух шагов, другой поток может выполнить оба шага, и тогда у вас будет проблема с неверными данными.

Класс Interlocked по существу объединяет два вышеупомянутых шага в один шаг, обеспечивая атомарную операцию. Теперь вам не нужно беспокоиться о потоках, так как это одна операция, которая не может быть прервана другим потоком.

Чтобы ответить на ваш вопрос, выглядит так converter.telerik.com вещь слишком консервативна в отношении проблем с многопоточностью. WAAAY чрезмерно консервативный. Я бы вернул код i-- если тот же экземпляр i не мутирует одновременно из нескольких потоков.

Единственная причина, по которой я вижу это

Interlocked.Decrement Метод

Уменьшает указанную переменную и сохраняет результат как элементарную операцию.

Другие вопросы по тегам