Подтвердить что ты не робот

Блокировка Mutex: что означает "блокировка"?

Я читал многопоточность и доступ к общим ресурсам, и одна из многих (для меня) новых концепций - это блокировка мьютекса. То, что я не могу найти, - это то, что на самом деле происходит с потоком, который находит "критический раздел" заблокирован. Во многих местах говорится, что поток "блокируется", но что это значит? Будет ли он приостановлен и возобновится ли он при снятии блокировки? Или он повторит попытку на следующей итерации цикла запуска?

Причина, по которой я спрашиваю, заключается в том, что я хочу иметь предоставленные системой события (мышь, клавиатура и т.д.), которые (apparantly) поставляются в основном потоке, которые будут обрабатываться в очень конкретной части цикла запуска мой вторичный поток. Таким образом, независимо от того, какое событие доставляется, я останавливаюсь в своей собственной структуре данных. Очевидно, что для структуры данных требуется блокировка мьютекса, поскольку она изменяется обоими потоками. Недостающая часть головоломки: что происходит, когда событие передается в функцию в основном потоке, я хочу поставить его в очередь, но очередь заблокирована? Будет ли приостановлен основной поток или он просто перепрыгнет через заблокированную секцию и выйдет из сферы действия (проиграв событие)?

4b9b3361

Ответ 1

Заблокировано означает, что выполнение застряло там; Как правило, поток сбрасывается системой и возвращает процессор другому потоку. Когда поток заблокирован, пытаясь получить мьютекс, выполнение возобновляется при освобождении мьютекса, хотя поток может блокироваться снова, если другой поток захватывает мьютекс, прежде чем он сможет.

Как правило, существует функция try-lock, которая, если возможно, захватывает мьютекс, а если нет, возвращается ошибка. Но в конечном итоге вам придется переместить текущее событие в эту очередь. Кроме того, если вы задерживаете перенос событий в поток, в котором они обрабатываются, приложение будет не реагировать независимо.

Очередь на самом деле является одним из случаев, когда вы можете обойтись без использования мьютекса. Например, Mac OS X (и, возможно, iOS) предоставляет функции OSAtomicEnqueue() и OSAtomicDequeue() (см. man atomic или <libkern/OSAtomic.h>), которые используют атомные операции, специфичные для процессора, чтобы избежать блокировки.

Но почему бы просто не обработать события в основном потоке как часть основного цикла цикла?

Ответ 2

Самый простой способ подумать, что заблокированный поток помещается в состояние ожидания ( "спящего" ) до тех пор, пока мьютекс не будет выпущен потоком, удерживающим его. В этот момент операционная система "пробудит" один из потоков, ожидающих мьютекс, и позволит ему приобрести его и продолжить. Это как если бы ОС просто помещала заблокированный поток на полку, пока у него не было того, что нужно продолжить. Пока ОС не выдержит поток с полки, он ничего не делает. Точная реализация - какая нить идет дальше, независимо от того, все ли они проснулись или они поставлены в очередь - будет зависеть от вашей ОС и того, какой язык/фрейм вы используете.

Ответ 3

Блокировка означает именно это. Он заблокирован. Он не будет действовать до тех пор, пока он не сможет. Вы не говорите, какой язык вы используете, но в большинстве языков/библиотек есть блокирующие объекты, где вы можете "попытаться" сделать блокировку, а затем продолжить и сделать что-то другое в зависимости от того, преуспели вы или нет.

Но, например, в синхронизированных блоках Java, ваш поток остановится до тех пор, пока он не сможет получить монитор (мьютекс, блокировка). Интерфейс java.util.concurrent.locks.Lock описывает объекты блокировки, которые имеют большую гибкость в плане обнаружения блокировки.

Ответ 4

Слишком поздно ответить, но я могу облегчить понимание. Я больше говорю из перспективы реализации, а не из теоретических текстов.

Слово "блокировка" является своего рода техническим омонимом. Люди могут использовать его для сна или просто ожидания. Этот термин следует понимать в контексте использования.

Блокировка означает Ожидание. Предположим, что в системе SMP нить A хочет получить спин-блокировку, удерживаемую каким-либо другим потоком B. Один из механизмов - отключить превенцию и продолжать вращаться на процессоре, если B получает его. Другим механизмом, вероятно, является эффективный, чтобы позволить другим потокам использовать процессор, в случае, если B не получает его в простых попытках. Поэтому мы расписываем поток B (когда включено preemption) и передаем процессор другому потоку C. В этом случае поток B просто ждет в очереди планировщика и возвращается со своим ходом. Поймите, что B не спит, просто ждут скорее пассивно, а не ожидают и оживляют циклы процессора. В системах BSD и Solaris существуют такие структуры данных, как турникеты, чтобы реализовать эту ситуацию.

Блокировка означает "Спящий" . Если поток B вместо этого сделал системный вызов, например read(), ожидающий данные из сетевого сокета, он не может действовать до тех пор, пока он не получит его. Поэтому некоторые тексты случайно используют блокировку слов как "... заблокированные для ввода-вывода" или "... при блокировании системного вызова". Собственно, нить В скорее спит. Существуют специальные структуры данных, известные как очереди сна - такие же, как роскошные комнаты ожидания в воздушных портах:-). Поток будет разбужен, когда ОС обнаружит доступность данных, так же как и обслуживающий зал ожидания.