Почему библиотеки реализуют свои собственные основные блокировки на окнах? - PullRequest
4 голосов
/ 10 августа 2009

Windows предоставляет ряд объектов, полезных для синхронизации потоков, таких как события (с SetEvent и WaitForSingleObject), мьютексы и критические секции.

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

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

Ответы [ 5 ]

14 голосов
/ 10 августа 2009

Библиотеки не реализуют свои собственные блокировки. Это почти невозможно без поддержки ОС.

То, что они делают , - это просто обертывание механизмов блокировки, предоставляемых ОС.

Boost делает это по нескольким причинам:

  • Они могут предоставить гораздо более качественно разработанный API блокировки, используя преимущества функций C ++. При этом Windows API - это только C, и не очень хорошо разработанный C.
  • Они могут предложить степень переносимости. тот же Boost API можно использовать, если вы запускаете приложение на компьютере с Linux или на Mac. Собственный API Windows, очевидно, специфичен для Windows.
  • Механизмы, предоставляемые Windows, имеют явный недостаток: они требуют, чтобы вы включили windows.h, которого вы можете избежать по большому количеству причин, не в последнюю очередь из-за его чрезмерного злоупотребления макросами, загрязняющего глобальное пространство имен.
4 голосов
/ 10 августа 2009

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

2 голосов
/ 15 августа 2009

Иногда могут быть веские причины для реализации ваших собственных блокировок, которые не используют объекты синхронизации ОС Windows. Но это «острая палка». Легко совать себя в ногу.

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

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

Я не уверен, что куплю аргумент переносимости. Переносимые библиотеки часто имеют уровень переносимости ОС, который абстрагирует различные API-интерфейсы ОС для синхронизации. Если вы имеете дело с блокировками, семантически можно сделать pthread_mutex так же, как Windows Mutex или критический раздел на уровне абстракции. Здесь есть некоторые исключения, но для большинства людей это правда. Если вы имеете дело с переменными условий Windows Events или POSIX, то их сложнее абстрагировать. (В Vista были введены условные переменные в стиле POSIX, но не многие разработчики программного обеспечения для Windows могут требовать Vista ...)

2 голосов
/ 10 августа 2009
  1. Во многих библиотеках (также называемых Boost) вам нужно писать код платформы corss. Таким образом, использование WaitForSingleObject и SetEvent запрещено. Кроме того, существуют общие идиомы, такие как Мониторы, Условия, которые Win32 API пропускает (но это может быть реализовано с использованием этих основных примитивов)
  2. Некоторые структуры данных без блокировки, такие как атомный счетчик, очень полезны; например: boost::shared_ptr использует их, чтобы сделать его потокобезопасным без издержек критической секции, большинство компиляторов (не msvc) используют атомарные счетчики для реализации потокового безопасного копирования при записи std::string.
  3. Некоторые вещи, такие как очереди, могут быть очень эффективно реализованы поточно-безопасным способом без блокировок вообще, что может значительно повысить производительность в некоторых приложениях.
1 голос
/ 10 августа 2009

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

...