Поскольку wait () будет возвращаться один раз при каждом вызове post (), семафоры - это базовая модель производитель-потребитель - самая простая форма сообщения между потоками, за исключением, возможно, сигналов. Они используются для того, чтобы один поток мог сообщить другому потоку, что произошло что-то, в чем он заинтересован (и сколько раз), и для управления доступом к ресурсам, которые могут иметь не более фиксированного конечного числа пользователей. Они предлагают гарантии заказа, необходимые для многопоточного кода.
Мьютексы делают то, что говорят на жестяной банке - «взаимное исключение». Они гарантируют, что право на доступ к некоторому ресурсу «удерживается» только в потоке за раз. Это дает гарантии атомарности и порядка, необходимого для многопоточного кода. В большинстве операционных систем они также предлагают достаточно сложное поведение официанта, в частности, чтобы избежать инверсии приоритетов.
Обратите внимание, что семафор можно легко использовать для реализации взаимного исключения, но, поскольку у семафора нет «потока владельца», вы не получите избежание инверсии приоритета с семафорами. Поэтому они не подходят для всех видов применения, для которых требуется «замок».
Блокировки ReaderWriter - это оптимизация мьютексов, в случаях, когда у вас будет много споров, большинство обращений доступно только для чтения, и одновременные чтения допустимы для защищаемой структуры данных. В таких случаях исключение требуется только в том случае, если в дело вовлечен писатель - читателей не нужно исключать друг из друга. Чтобы продвинуть читателя к писателю, все остальные читатели должны завершить (или прервать и начать ждать, чтобы повторить попытку, если они также хотят стать писателями), прежде чем блокировка писателя будет получена. Блокировки ReaderWriter, вероятно, будут медленнее в тех случаях, когда они не быстрее, из-за дополнительного учета, который они выполняют над мьютексами.
Переменные условия предназначены для того, чтобы позволить потокам ожидать определенных фактов или комбинаций фактов, являющихся истинными, где рассматриваемое условие является более сложным, чем просто «оно было выковано», как для семафоров, или «никто другой не использует» это "для мьютексов и писательской части блокировок читатель-писатель, или" ни один писатель не использует это "для читательской части блокировок читатель-писатель. Они также используются там, где условия запуска различны для разных ожидающих потоков, но зависят от одного или всех одинаковых состояний (областей памяти или чего-либо еще).
Спин-блокировки предназначены для тех случаев, когда вы будете ждать очень короткий промежуток времени (например, несколько циклов) на одном процессоре или ядре, в то время как другое ядро (или часть оборудования, например шина ввода-вывода) одновременно делает какую-то работу, которая вас волнует. В некоторых случаях они дают повышение производительности по сравнению с другими примитивами, такими как семафоры или прерывания, но должны использоваться с особой осторожностью (поскольку алгоритмы без блокировок трудны в современных моделях памяти) и только тогда, когда это необходимо (поскольку яркие идеи избегают системных примитивов) часто бывают преждевременные оптимизации).
Кстати, эти ответы не являются специфичными для C # (отсюда, например, комментарий о «большинстве ОС»). Ричард замечательно отмечает, что в C # вы должны использовать простые старые блокировки, где это уместно. Я считаю, что мониторы - это пара переменных мьютекс / условие, объединенная в один объект.