2015-10-30 4 views
12

Я понимаю, что поток, который ожидает условную переменную, атомистически освобождает блокировку и переходит в режим сна, пока не пробуждается условным сигналом из другого потока (когда выполняется конкретное условие). После того, как он просыпается, он атомарно повторно приобретает замок (каким-то волшебным образом) и обновляет по мере необходимости и разблокирует критический раздел.Как выполняется условие conditional_wait() на уровне ядра и оборудования/сборки?

Было бы здорово, если бы кто-нибудь мог объяснить, как эта процедура conditional_wait() реализована на ядре и на уровне оборудования/сборки?

Каким образом блокировка освобождается и повторно приобретается атомарно? Как это обеспечивает ядро?

Что здесь сон здесь означает? Означает ли это, что контекст переключается на другой процесс/поток?

Во время нитьного сна, как это происходит поток пробуждается сигналом, реализованным на уровне ядра и если для этих механизмов предусмотрена какая-либо аппаратная поддержка?

Edit:

кажется "futex" парень, управляющий этим материалом ожидания/сигнала. Чтобы сузить мой вопрос: Как системная система futex для ожидания и уведомления переменных условия реализована/работает на низком уровне?

+0

В системе Linux источника, от стандартного уровня библиотеки вплоть до ядра, все открыто и свободно доступен. Это займет некоторое время, чтобы просеять, но это невозможно. –

+1

В системах Linux связь между пользовательским пространством и ядром обычно выполняется с помощью инструмента futex. Он объединяет атомные обновления с организованным ядром ожидания. Вы должны быть в состоянии найти много документации о futexes. –

+0

Где он заявляет, что * повторный захват * блокировки после ожидания является атомарным? Мангаж, конечно же, нет. – EOF

ответ

11

На высоком уровне (и поскольку вы просите этот quesiton, высокий уровень - это то, что вам нужно), это не так сложно. Во-первых, вам нужно знать уровни ответственности. Есть в основном 3 слоев: уровень

  • Оборудование - как правило, то, что может быть закодировано в одной команде ASM
  • уровня ядра - то, что ядро ​​ОС делает уровень
  • Application - то, что делает приложение

Как правило, эти обязанности не перекрываются - ядро ​​не может делать то, что может сделать только оборудование, аппаратное обеспечение не может делать то, что может сделать только ядро. Имея это в виду, полезно помнить, что когда дело доходит до блокировки, об этом мало известно об аппаратных средствах. Это в значительной степени сводится к

  • Атомная арифметика - оборудование может блокировать определенную область памяти (убедитесь, что к ней не обращаются никакие другие потоки), выполнить арифметическую операцию и разблокировать область. Это может работать только на арифметике, поддерживаемой чипом (без квадратных корней!) И на размерах, поддерживаемых аппаратным обеспечением
  • Загрязнения памяти или ограждения, то есть вводят барьер в потоке инструкций, так что когда CPU переупорядочивает инструкции или использует кэши памяти, они не будут пересекать эти ограждения, и кеш будет свежим.
  • Условная настройка (сравнение и установка) - установить область памяти в значение A, если она есть B и сообщить о состоянии этой операции (был ли он установлен или нет)

Это почти все CPU может сделать. Как вы видите, здесь нет futex, mutex или условных переменных. Этот материал сделан ядром, имеющим поддерживаемые процессором операции в его распоряжении.

Давайте посмотрим на очень высоком уровне, как ядро ​​может реализовать вызов futex.Фактически, futex немного сложнее, потому что это смесь вызовов уровня пользователя и вызовов уровня ядра по мере необходимости. Давайте рассмотрим «чистый» мьютекс, реализованный исключительно в пространстве ядра. На высоком уровне это будет достаточно показательным.

Когда mutex изначально создан, ядро ​​связывает с ним область памяти. Эта область будет удерживать значение блокировки или разблокировки мьютекса. Позже ядро ​​попросит заблокировать мьютекс, он сначала инструктирует CPU о выделении памяти. Мьютекс должен выступать в качестве барьера, так что все прочитанное/wrttten после того, как мьютекс будет приобретен (или выпущен), будет видимым для остальных процессоров. Затем он использует поддерживаемую процессором команду сравнения и настройки для установки значения области памяти в 1, если она была установлена ​​в 0. (есть более сложные повторные мьютексы, но давайте не будем усложнять изображение ими). Гарантируется процессором, что даже если более одного потока пытается сделать это одновременно, только один будет успешным. Если операция завершается успешно, мы теперь «удерживаем мьютекс». После того, как ядро ​​попросит освободить мьютекс, область памяти установлена ​​в 0 (нет необходимости делать это условно, поскольку мы знаем, что мы удерживаем мьютекс!), И выдается еще один барьер памяти. Ядро также обновляет статус мьютекса в его таблицах - см. Ниже.

Если блокировка мьютекса не удалась, ядро ​​добавляет поток в свои таблицы, которые перечисляют потоки, ожидающие выхода определенного мьютекса. Когда мьютекс освобожден, ядро ​​проверяет, какие потоки (-ы) ждут этот мьютекс, и «расписания» (т. Е. Готовятся к выполнению), один из них (в случае, если есть более одного, который будет запланирован или пробужден, зависит от множество факторов, в простейшем случае это просто случайное). Запланированный поток начинает выполняться, снова блокирует мьютекс (в этот момент он может снова сработать!), И цикл жизни продолжается.

Надеется, что это делает, по крайней мере половину смысла :)

+0

Большое спасибо за подробный ответ! Делает многое ясно о блокировке. У меня есть еще несколько разъяснений. Что ** спит ** после разблокировки на самом деле означает? Это означает переход на другой процесс/поток ядра?как эта нить пробуждается ** сигнализацией **? Что означает сигнализация спящего потока? Как это реализовано. – Shyam

+1

'sleep' означает, что поток выдает вызов функции сна (скажем,« нанослеп »), поддерживаемой ядром. Увидев этот вызов, планировщик берет поток, который выдает вызов от выполнения, и планирует следующее выполнение, которое произойдет после истечения таймаута ожидания. Обратите внимание, что если вы не говорите об истинной системе реального времени, поток не будет выполняться ТОЧНО после таймаута. Он будет выполнен не до таймаута! Сигнал - это запись в сигнальных таблицах внутри ядра. Как только ядро ​​увидит его, он вызывает функцию обработки сигналов, определенную в потоке. – SergeyA

Смежные вопросы