Стоит ли реализовывать «бенафоры» на современных ОС? - PullRequest
1 голос
/ 28 октября 2009

В те времена, когда я работал программистом на BeOS, я прочитал эту статью , написанную Бенуа Шиллингсом, описывающую, как создать «бенафор»: метод использования атомарной переменной для принудительного применения критической секции, которая устраняет необходимость получить / освободить мьютекс в обычном (без конфликтов) случае.

Я подумал, что это довольно умно, и кажется, что вы могли бы сделать тот же трюк на любой платформе, которая поддерживает атомарный прирост / декремент.

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

Кто-нибудь знает, использует ли этот трюк современные API блокировки (например, pthread_mutex_lock () / pthread_mutex_unlock ())? А если нет, то почему?

Ответы [ 2 ]

1 голос
/ 28 октября 2009

То, что описывает ваша статья, сегодня широко используется. Чаще всего он называется " Critical Section " и состоит из заблокированной переменной, набора флагов и внутреннего объекта синхронизации (Mutex, если я правильно помню). Как правило, в сценариях с небольшим количеством конфликтов критический раздел выполняется полностью в пользовательском режиме, без участия объекта синхронизации ядра. Это гарантирует быстрое выполнение. Когда конкуренция высока, объект ядра используется для ожидания, что освобождает временной интервал, проводящий для более быстрого оборота.

Как правило, в настоящее время очень мало смысла в реализации примитивов синхронизации. Операционные системы поставляются с большим разнообразием таких объектов, и они оптимизированы и протестированы в значительно более широком диапазоне сценариев, чем может себе представить один программист. Буквально годы требуются, чтобы изобрести, внедрить и протестировать хороший механизм синхронизации. Это не значит, что нет смысла пытаться:)

0 голосов
/ 07 декабря 2009

Java AbstractQueuedSynchronizer (и его брат AbstractQueuedLongSynchronizer) работает аналогично, или, по крайней мере, может быть реализован аналогичным образом. Эти типы формируют основу для нескольких примитивов параллелизма в библиотеке Java, таких как ReentrantLock и FutureTask.

Он работает посредством использования атомного целого числа для представления состояния. Блокировка может определить значение 0 как разблокированное и 1 как заблокированное. Любой поток, желающий получить блокировку, пытается изменить состояние блокировки с 0 на 1 с помощью атомарной операции сравнение и установка ; если попытка не удалась, текущее состояние не равно 0, что означает, что блокировка принадлежит другому потоку.

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

Большинство этого механизма могут быть реализованы в виде атомного целого числа, представляющего состояние, а также пары атомных указателей для каждой очереди ожидания. Фактическое планирование того, какие потоки будут бороться за проверку и изменение переменной состояния (например, через AbstractQueuedSynchronizer#tryAcquire(int)), выходит за рамки такой библиотеки и попадает в планировщик хост-системы.

...