futex - быстрая
блокировка
в
пользовательском
пространстве
#include <linux/futex.h>
Ядро Linux
предоставляет
фьютексы (futexes,
«быстрые
мьютексы (mutexes,
взаимоисключающие
блокировки)
в
пользовательском
пространстве»)
в качестве
строительного
блока для
быстрой
блокировки
в
пользовательском
пространстве
и
семафоров.
Фьютексы
очень
просты и
полезны
для
создания
высокоуровневых
абстракций
блокировок,
таких как
мьютексы,
условных
переменных,
блокировок
чтения-записи,
барьеров и
семафоров.
Большинство
программистов,
фактически,
не
используют
фьютексы
напрямую, а
полагаются
на
системные
библиотеки,
которые на
них
построены,
такие как Native POSIX
Thread Library (NPTL)
(смотрите
pthreads(7)).
Фьютекс
отождествляется
с участком
памяти,
который
может быть
общим для
процессов
или нитей. В
этих
процессах
фьютекс
может быть
доступен
по разным
адресам. В
своей
основе
фьютекс
имеет
семантику
семафора;
это
счётчик,
который
можно
увеличивать
и
уменьшать
атомарно;
процессы
могут
ждать пока
значение
не станет
положительным.
Работа с
фьютексом
выполняется
полностью
в
пользовательском
пространстве
при
отсутствии
конфликта
(noncontended case). Ядро
привлекается
только для
разрешения
конфликтов.
Так как все
проектные
решения
стремятся
к
отсутствию
конфликтов,
фьютексы
также
оптимизированы
под эту
ситуацию.
В своей
основе
фьютекс —
это целое
число,
которое
изменяется
только
атомарными
инструкциями
ассемблера.
Это целое
число
размером 4
байта на
всех
платформах.
Процессы
могут
совместно
использовать
это число
посредством
mmap(2),
сегментов
общей
памяти или
общего
пространства
памяти (share memory space, в
этом
случае
приложение,
обычно,
называют
многонитевым).
Любое
действие с
фьютексом
начинается
в
пользовательском
пространстве,
но может
потребовать
обращения
к ядру
через
системный
вызов
futex(2).
Для
«установки»
фьютекса
выполняются
соответствующие
ассемблерные
инструкции,
которые
заставляют
ЦП машины
атомарно
увеличить
целое
число.
Далее
проверяется,
было ли
действительно
изменено
значение с 0
на 1, то есть
не было
ожидающих
и операция
выполнена.
Это
бесконфликтный
вариант,
выполняется
быстро и
должен
возникать
чаще всего.
При
возникновении
конфликта,
атомарное
увеличение
изменяет
счётчик с -1
(или
другого
отрицательного
числа). Это
означает,
что есть
ожидающие.
В
пользовательском
пространстве
теперь
нужно
присвоить
счётчику 1 и
дать
команду
ядру
пробудить
всех
ожидающих
с помощью
операции
FUTEX_WAKE.
Ожидание
фьютекса,
его
«сброс»,
является
обратной
операцией.
Происходит
атомарное
уменьшение
счётчика и
проверка
того, стал
ли он равен 0,
то есть
операция
выполнена
и фьютекс
был
неконфликтным.
Во всех
других
случаях,
процесс
должен
присвоить
счётчику -1 и
запросить
ядро об
ожидании
другого
процесса,
устанавливающего
фьютекс.
Это
выполняется
с помощью
операции
FUTEX_WAIT.
В
системном
вызове
futex(2)
можно
указать
время
ожидания,
то есть как
долго ядро
должно
ждать
установку
фьютекса, В
этом
случае
семантика
более
сложна и
программисту
нужно
обратиться
к
futex(2). Это
тоже самое
что и
ожидания
асинхронного
фьютекса.
Впервые
поддержка
фьютексов
появилась
в Linux 2.5.7, но с
другой
семантикой.
Текущая
семантика
используется
в Linux с версии
2.5.40.
Ещё раз
повторим: в
чистом
виде
фьютексы
не
являются
лёгкой в
использовании
абстракцией
для
конечных
пользователей.
Использующие
их
программисты
должны
иметь
хороший
запас
знаний об
ассемблере
и уметь
читать
исходный
код
библиотеки
фьютексов
для
пользовательского
пространства,
указанной
далее.
В этой
справочной
странице
показано
самое
распространённое
использование
примитивов
futex(2), которое
ни в коем
случае не
единственное.
clone(2),
futex(2),
get_robust_list(2),
set_robust_list(2),
set_tid_address(2),
pthreads(7)
Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux (proceedings
of the Ottawa Linux Symposium 2002), futex example library, futex-*.tar.bz2
https://mirrors.kernel.org/pub/linux/kernel/people/rusty/
Русский
перевод
этой
страницы
руководства
был сделан
Azamat Hackimov <
[email protected]>, Dmitry Bolkhovskikh
<
[email protected]>, Yuri Kozlov <
[email protected]> и
Иван
Павлов <
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]