Джонсон Харт - Системное программирование в среде Windows
- Название:Системное программирование в среде Windows
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2005
- Город:Москва • Санкт-Петербург • Киев
- ISBN:5-8459-0879-5
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Джонсон Харт - Системное программирование в среде Windows краткое содержание
Эта книга посвящена вопросам разработки приложений с использованием интерфейса прикладного программирования операционных систем компании Microsoft (Windows 9х, Windows XP, Windows 2000 и Windows Server 2003). Основное внимание уделяется базовым системным службам, включая управление файловой системой, процессами и потоками, взаимодействие между процессами, сетевое программирование и синхронизацию. Рассматривается методика переноса приложений, написанных в среде Win32, в среду Win64. Подробно описываются все аспекты системы безопасности Windows и ее практического применения. Изобилие реальных примеров, доступных также и на Web-сайте книги, существенно упрощает усвоение материала.
Книга ориентирована на разработчиков и программистов, как высокой квалификации, так и начинающих, а также будет полезна для студентов соответствующих специальностей.
Системное программирование в среде Windows - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Использование семафоров
Классической областью применения семафоров является управление распределением конечных ресурсов, когда значение счетчика семафора ассоциируется с определенным количеством доступных ресурсов, например, количеством сообщений, находящихся в очереди. Тогда максимальное значение счетчика соответствует максимальному размеру очереди. Таким образом, производитель помещает сообщение в буфер и вызывает функцию ReleaseSemaphore, обычно с увеличением значения счетчика на 1 (cReleaseCount). Потоки потребителя будут ожидать перехода семафора в сигнальное состояние, получая сообщения и уменьшая значения счетчика.
Вслед за рассмотрением программы 9.1 обсуждается другой важный случай применения семафоров, когда они используются для ограничения количества рабочих потоков, фактически выполняющихся в любой момент времени, что позволяет снизить состязательность между ними, а в некоторых случаях — повысить производительность. Эта методика, в которой используются дроссели семафоров (semaphore throttles), обсуждается в главе 9.
Опасность возникновения условий состязаний в программе sortMT (программа 7.2) иллюстрирует другое возможное применение семафоров, связанное с управлением точным количеством потоков, которые должны находиться в пробужденном состоянии. Можно создать все потоки, не приостанавливая их. После этого все они сразу же переходят к ожиданию перехода в сигнальное состояние семафора, инициализированного значением 0. Далее, главный поток вместо того, чтобы освобождать потоки, просто вызывает функцию ReleaseCount с увеличением счетчика, например, на 4 (или на любое другое значение, соответствующее количеству потоков), в результате чего возможность выполняться получат четыре потока.
Несмотря на все удобства, которые сулит использование семафоров, они являются в некотором смысле излишними в том смысле, что мьютексы и события (описанные в одном из следующих разделов), при условии их совместного использования, предлагают гораздо более широкие возможности, чем семафоры. Более подробная информация по этому поводу содержится в главе 10.
Ограниченность семафоров
В Windows существуют важные ограничения, касающиеся реализации семафоров. Например, каким образом поток может потребовать, чтобы счетчик семафора уменьшился на 2? Для этого поток мог бы организовать ожидание два раза подряд, как показано ниже, но эта операция не была бы атомарной, поскольку в промежутке между двумя вызовами функции ожидания данный поток может быть вытеснен. В результате этого, как описывается ниже, может наступить взаимоблокировка (deadlock) потоков.
/* hsem – дескриптор семафора. Максимальное значение счетчика семафора равно 2. */
…
/* Уменьшить значение счетчика семафора на 2. */
WaitForSingleObject(hSem, INFINITE);
WaitForSingleObject(hSem, INFINITE);
…
/* Увеличить значение счетчика семафора на 2. */
ReleaseSemaphore(hSem, 2, &PrevCount);
Чтобы увидеть, каким образом в подобной ситуации может возникнуть взаимоблокировка, предположим, что максимальное и начальное значения счетчика устанавливаются равными 2 и что первый из двух потоков завершает первый цикл ожидания, а затем вытесняется. Далее второй поток может завершить первый цикл ожидания и уменьшить значение счетчика до 0. Оба потока окажутся блокированными на неопределенное время, поскольку ни одна из них не сможет выполнить второй цикл ожидания. Такая простая ситуация взаимоблокировки является довольно типичной.
Один из возможных вариантов правильного решения заключается в том, чтобы защитить циклы ожидания при помощи мьютекса или объекта CRITI-CAL_SECTION, как показано в приведенном ниже фрагменте программного кода:
/* Уменьшаем значение счетчика семафора на 2. */
EnterCriticalSection(&csSem);
WaitForSingleObject(hSem, INFINITE);
WaitForSingleObject(hSem, INFINITE);
LeaveCriticalSection (&csSem);
…
ReleaseSemaphore(hSem, 2, &PrevCount);
Но и эта реализация, в таком общем виде, страдает ограничениями. Предположим, например, что в счетчике семафора остается две единицы, и потоку А необходимы три единицы, а потоку В — только две. Если первой начнет выполняться поток А, то он выполнит два цикла ожидания и блокируется на третьем, продолжая владеть мьютексом. При этом поток В, которому были необходимы только две единицы, по-прежнему будет оставаться блокированным.
Казалось бы, можно воспользоваться функцией WaitForMultipleObjects с использованием одного и того же дескриптора семафора в нескольких элементах массива дескрипторов. Однако такое предложение было бы неудачным по двум причинам. Прежде всего, обнаружив, что два дескриптора указывают на один и тот же объект, функция WaitForMultipleObjects завершится с ошибкой. Более того, даже если значение счетчика семафора будет составлять только 1, сигнализироваться будут все дескрипторы, что противоречит самой исходной цели.
Полное решение проблемы множественных циклов ожидания предлагается в упражнении 10.11.
Проектировать семафоры Windows было бы гораздо удобнее, если бы существовала возможность выполнять множественные циклы ожидания в виде одной атомарной операции (atomic multiple-wait operation).
События
Последним из рассматриваемых нами типов объектов синхронизации ядра являются события (events). Объекты события используются для того, чтобы сигнализировать другим потокам о наступлении какого-либо события, например, о появлении нового сообщения.
Важной дополнительной возможностью, обеспечиваемой объектами событий, является то, что переход в сигнальное состояние единственного объекта события способен вывести из состояния ожидания одновременно несколько потоков. Объекты события делятся на сбрасываемые вручную и автоматически сбрасываемые, и это их свойство устанавливается при вызове функции CreateEvent.
• Сбрасываемые вручную события (manual-reset events) могут сигнализировать одновременно всем потокам, ожидающим наступления этого события, и переводятся в несигнальное состояние программно.
• Автоматически сбрасываемые события (auto-reset event) сбрасываются самостоятельно после освобождения одного из ожидающих потоков, тогда как другие ожидающие потоки продолжают ожидать перехода события в сигнальное состояние.
События используют пять новых функций: CreateEvent, OpenEvent, SetEvent, ResetEvent и CreateEvent.
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpsa, BOOL bManualReset, BOOL bInitialState, LPTCSTR lpEventName)
Чтобы создать событие, сбрасываемое вручную, необходимо установить значение параметра bManualReset равным True. Точно так же, чтобы сделать начальное состояние события сигнальным, установите равным True значение параметра bInitialState. Для открытия именованного объекта события используется функция OpenEvent, причем это может сделать и другой процесс.
Читать дальшеИнтервал:
Закладка: