На высоком уровне (и поскольку вы просите этот quesiton, высокий уровень - это то, что вам нужно), это не так сложно. Во-первых, вам нужно знать уровни ответственности. Есть в основном 3 слоев: уровень
- Оборудование - как правило, то, что может быть закодировано в одной команде ASM
- уровня ядра - то, что ядро ОС делает уровень
- Application - то, что делает приложение
Как правило, эти обязанности не перекрываются - ядро не может делать то, что может сделать только оборудование, аппаратное обеспечение не может делать то, что может сделать только ядро. Имея это в виду, полезно помнить, что когда дело доходит до блокировки, об этом мало известно об аппаратных средствах. Это в значительной степени сводится к
- Атомная арифметика - оборудование может блокировать определенную область памяти (убедитесь, что к ней не обращаются никакие другие потоки), выполнить арифметическую операцию и разблокировать область. Это может работать только на арифметике, поддерживаемой чипом (без квадратных корней!) И на размерах, поддерживаемых аппаратным обеспечением
- Загрязнения памяти или ограждения, то есть вводят барьер в потоке инструкций, так что когда CPU переупорядочивает инструкции или использует кэши памяти, они не будут пересекать эти ограждения, и кеш будет свежим.
- Условная настройка (сравнение и установка) - установить область памяти в значение A, если она есть B и сообщить о состоянии этой операции (был ли он установлен или нет)
Это почти все CPU может сделать. Как вы видите, здесь нет futex, mutex или условных переменных. Этот материал сделан ядром, имеющим поддерживаемые процессором операции в его распоряжении.
Давайте посмотрим на очень высоком уровне, как ядро может реализовать вызов futex.Фактически, futex немного сложнее, потому что это смесь вызовов уровня пользователя и вызовов уровня ядра по мере необходимости. Давайте рассмотрим «чистый» мьютекс, реализованный исключительно в пространстве ядра. На высоком уровне это будет достаточно показательным.
Когда mutex изначально создан, ядро связывает с ним область памяти. Эта область будет удерживать значение блокировки или разблокировки мьютекса. Позже ядро попросит заблокировать мьютекс, он сначала инструктирует CPU о выделении памяти. Мьютекс должен выступать в качестве барьера, так что все прочитанное/wrttten после того, как мьютекс будет приобретен (или выпущен), будет видимым для остальных процессоров. Затем он использует поддерживаемую процессором команду сравнения и настройки для установки значения области памяти в 1, если она была установлена в 0. (есть более сложные повторные мьютексы, но давайте не будем усложнять изображение ими). Гарантируется процессором, что даже если более одного потока пытается сделать это одновременно, только один будет успешным. Если операция завершается успешно, мы теперь «удерживаем мьютекс». После того, как ядро попросит освободить мьютекс, область памяти установлена в 0 (нет необходимости делать это условно, поскольку мы знаем, что мы удерживаем мьютекс!), И выдается еще один барьер памяти. Ядро также обновляет статус мьютекса в его таблицах - см. Ниже.
Если блокировка мьютекса не удалась, ядро добавляет поток в свои таблицы, которые перечисляют потоки, ожидающие выхода определенного мьютекса. Когда мьютекс освобожден, ядро проверяет, какие потоки (-ы) ждут этот мьютекс, и «расписания» (т. Е. Готовятся к выполнению), один из них (в случае, если есть более одного, который будет запланирован или пробужден, зависит от множество факторов, в простейшем случае это просто случайное). Запланированный поток начинает выполняться, снова блокирует мьютекс (в этот момент он может снова сработать!), И цикл жизни продолжается.
Надеется, что это делает, по крайней мере половину смысла :)
В системе Linux источника, от стандартного уровня библиотеки вплоть до ядра, все открыто и свободно доступен. Это займет некоторое время, чтобы просеять, но это невозможно. –
В системах Linux связь между пользовательским пространством и ядром обычно выполняется с помощью инструмента futex. Он объединяет атомные обновления с организованным ядром ожидания. Вы должны быть в состоянии найти много документации о futexes. –
Где он заявляет, что * повторный захват * блокировки после ожидания является атомарным? Мангаж, конечно же, нет. – EOF