(Это ответ на обновленную версию вопроса с рабочими потоками и неприятными спин-ожиданиями вместо выхода / thread.Join
)
Могут ли закомментированные утверждения в приведенном выше коде быть ложными?
Нет, все ваши Thread.MemoryBarrier()
кажутся избыточными и просто замедляют вас. ( Я не очень внимательно читал ваш код, но я думаю, что у вас есть потоки, ожидающие увидеть результат операции Interlocked из другого потока, прежде чем они прочитают / запишут другие данные.)
Interlocked.Increment(ref ready);
- это релиз / операция получения (фактически полный барьер памяти, например Thread.MemoryBarrier()
). Новое значение ref
не будет видно, пока не будут видны все предыдущие хранилища.
Interlocked.Read
- это операция получения: более поздние загрузки могут быть загружены только после значения вы получаете от этого. https://preshing.com/20120913/acquire-and-release-semantics/
Это дает вам освобождение / получение синхронизации без необходимости каких-либо явных / автономных барьеров памяти. ( Использует ли Interlocked.CompareExchange барьер памяти? ссылается на стандарт ECMA-335, поэтому мы знаем, что это переносимая гарантия, а не деталь реализации x86.)
Все оборудование модели памяти, через которые проходят потоки C ++ / C#, согласованы с кешем; вам не нужна явная очистка, чтобы видеть данные по потокам. Вам просто нужно убедиться, что компилятор не хранит значение в регистре и не хранит и не загружает его вообще.
В гипотетическом случае, когда требуется явная очистка, Interlocked сделает это за вас, чтобы сохранить модель памяти языка.