Я предлагаю вам взглянуть на структуру SpinLock
, поскольку она, кажется, делает именно то, что вы хотите.
Тем не менее, все это выглядит очень рискованно, но я попробую.
Вы, похоже, пытаетесь использовать 0
для обозначения "разблокировано" и 1
для обозначения "заблокировано".
В этом случае строка:
if (Interlocked.CompareExchange(ref locked, 1, inLock) == 1)
совсем не правильно. Он просто заменяет переменную locked
значением 1
(заблокировано), если ее текущее значение совпадает с последним разом, когда вы читаете ее через inLock = locked
(и, если это так, получает блокировку). Хуже того, входит в раздел взаимного исключения, если исходное значение было 1
(заблокировано), что является полной противоположностью того, что вы хотите делать .
На самом деле вы должны атомарно проверять, что блокировка не была взята (исходное значение == 0), и взять ее, если можете (новое значение == 1), используя 0
(разблокировано) как * 1027. * аргумент, а также значение для проверки возвращаемого значения:
if (Interlocked.CompareExchange(ref locked, 1, 0) == 0)
Теперь, даже если вы исправили это, мы также должны быть уверены, что метод List<T>.Add
будет «видеть» обновленное внутреннее состояние списка для правильного выполнения добавления. Я думаю Interlocked.CompareExchange
использует полный барьер памяти, который должен создать этот приятный побочный эффект, но на это действительно немного опасно полагаться (я никогда нигде не видел этого документированного).
Я настоятельно рекомендую держаться подальше от таких шаблонов с низким уровнем блокировки, за исключением самых тривиальных (и очевидно правильных) сценариев, если вы не являетесь настоящим экспертом в программировании с низким уровнем блокировки. Мы, простые смертные поймем это неправильно.
EDIT : обновлено значение сравнения до 0
.