Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
vazhnoe.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
843.48 Кб
Скачать

26. Синхронизация потоков в пределах одного процесса ос Windows. Ожидаемое условие (монитор Хора). Операции с ожидаемым условием. Пример использования ожидаемого условия для синхронизации потоков.

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

Условные переменные обеспечивают присущую Windows реализацию синхронизации набора потоков, ожидающих конкретного результата проверки условия. Хотя эта операция была возможна и с применением других методов синхронизации в пользовательском режиме, атомарного механизма для проверки результата проверки условия и для начала ожидания изменения этого результата не существовало. Это потребовало использования в отношении таких фрагментов кода этой дополнительной синхронизации. Поток пользовательского режима инициализирует условную переменную путем вызова функции InitializeConditionVariable для установки ее исходного состояния. Когда ему нужно инициировать ожидание, связанное с этой переменной, он вызывает функцию SleepConditionVariableCS, которая использует критический раздел (который поток должен инициализировать) для ожидания изменений переменной. После изменения переменной устанавливающий поток должен использовать функцию WakeConditionVariable (или функцию WakeAllConditionVariable). В результате этого вызова освобождается критический раздел либо одного, либо всех ожидающих потоков, в зависимости от того, которая из этих функция была использована. До условных переменных для отправки сигнала об изменении переменной, например состояния рабочей очереди, часто использовалось либо уведомительное событие, либо синхронизирующее событие (в Windows API они называются авто матическим перезапуском — auto-reset, или ручным перезапуском — manual-reset). Ожидание изменения требует получения, а затем освобождения критического раздела, сопровождаемого ожиданием события. После ожидания критический раздел должен быть получен повторно. Во время этих серий получений и освобождений у потока может быть переключен контекст, вызывая проблемы, если один из потоков называется PulseEvent. При использовании условных переменных получение критического раздела может быть поддержано приложением во время вызова функции SleepConditionVariableCS, и он может быть освобожден только после выполнения работы. Это делает код записи рабочей очереди (и подобных ей реализаций) более простым и предсказуемым. Внутри системы условные переменные могут рассматриваться как порт существующих алгоритмов пуш-блокировок, имеющихся в режиме ядра, с дополнительным усложнением в виде получения и освобождения критических разделов в API-функции SleepConditionVariableCS. Условные переменные по размеру равны указателям (точно так же, как и пуш-блокировки), избегают использования диспетчера, автоматически оптимизируют во время операций ожидания список ожиданий и защищают от сопровождений блокировки. Кроме того, условные переменные полностью используют события с ключом, а не обычный объект события, который бы использовался разработчиками по своему усмотрению, что еще больше оптимизирует код даже в случаях возникновения конкуренции.

27. Синхронизация потоков разных процессов с помощью объектов ядра. Понятие свободного и занятого состояния объекта ядра. Процедуры ожидания освобождения объекта ядра. Перевод объекта ядра в свободное состояние. Объекты синхронизации: блокировки, семафоры, события.

 

Почти все объекты ядра годятся и для решения задач синхронизации. В случае синхронизации потоков о каждом из этих объектов говорят, что он находится либо в свободном (signaled state), либо в занятом состоянии (nonsignaled state). Переход из одного состояния в другое осуществляется по правилам, определенным Microsoft для каждого из объектов ядра. Так, объекты ядра «процесс» сразу после создания всегда находятся в занятом состоянии. В момент завершения процесса операционная система автоматически освобождает его объект ядра «процесс», и он навсегда остается в этом состоянии.

Объект ядра «процесс» пребывает в занятом состоянии, пока выполняется сопоставленный с ним процесс, и переходит в свободное состояние, когда процесс завершается. Внутри этого объекта поддерживается булева переменная, которая при создании объекта инициализируется как FALSE («занято»). По окончании работы процесса операционная система меняет значение этой переменной на TRUE, сообщая тем самым, что объект свободен.

Если Вы пишете код, проверяющий, выполняется ли процесс в данный момент, Вам нужно лишь вызвать функцию, которая просит операционную систему проверить значение булевой переменной, принадлежащей объекту ядра «процесс». Тут нет ничего сложного. Вы можете также сообщить системе, чтобы та перевела Ваш поток в состояние ожидания и автоматически пробудила его при изменении значения булевой переменной с FALSE на TRUE. Тогда появляется возможность заставить поток в родительском процессе, ожидающий завершения дочернего процесса, просто заснуть до освобождения объекта ядра, идентифицирующего дочерний процесс. В дальнейшем Вы увидите, что в Windows есть ряд функций, позволяющих легко решать эту задачу. Я только что описал правила, определенные Microsoft для объекта ядра «процесс». Точно такие же правила распространяются и на объекты ядра «поток». Они тоже сразу после создания находятся в занятом состоянии. Когда поток завершается, операционная система автоматически переводит объект ядра «поток» в свободное состояние. Таким образом, используя те же приемы, Вы можете определить, выполняется ли в данный момент тот или иной поток. Как и объект ядра «процесс», объект ядра «поток» никогда не возвращается в занятое состояние. Следующие объекты ядра бывают в свободном или занятом состоянии:

·         процессы

·         уведомления об изменении файлов

·         потоки

·         события

·         задания

·         ожидаемые таймеры

·         файлы

·         семафоры

·         консольный ввод

·         мьютексы

Потоки могут засыпать и в таком состоянии ждать освобождения какого-либо объекта. Правила, по которым объект переходит в свободное или занятое состояние, зависят от типа этого объекта.

Wait функции позволяют потоку в любой момент приостановиться и ждать освобождения какого-либо объекта ядра. Из всего семейства этих функций чаще всего используется WaitForSingleObject:

DWORD WaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds);

Когда поток вызывает эту функцию, первый параметр, hObject, идентифицирует объект ядра, поддерживающий состояния «свободен занят». (То есть любой объект, упомянутый в списке из предыдущего раздела.) Второй параметр, dwMilliseconds, указывает, сколько времени (в миллисекундах) поток готов ждать освобождения объекта. Следующий вызов сообщает системе, что поток будет ждать до тех пор, пока не завершится процесс, идентифицируемый описателем

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

28. Синхронизация потоков разных процессов с помощью объектов ядра. Понятие свободного и занятого состояния объекта ядра. Процедуры ожидания освобождения объекта ядра. Ожидаемые таймеры. Оконные таймеры.

Почти все объекты ядра годятся и для решения задач синхронизации. В случае синхронизации потоков о каждом из этих объектов говорят, что он находится либо в свободном (signaled state), либо в занятом состоянии (nonsignaled state). Переход из одного состояния в другое осуществляется по правилам, определенным Microsoft для каждого из объектов ядра. Так, объекты ядра «процесс» сразу после создания всегда находятся в занятом состоянии. В момент завершения процесса операционная система автоматически освобождает его объект ядра «процесс», и он навсегда остается в этом состоянии.

Объект ядра «процесс» пребывает в занятом состоянии, пока выполняется сопоставленный с ним процесс, и переходит в свободное состояние, когда процесс завершается. Внутри этого объекта поддерживается булева переменная, которая при создании объекта инициализируется как FALSE («занято»). По окончании работы процесса операционная система меняет значение этой переменной на TRUE, сообщая тем самым, что объект свободен.

Если Вы пишете код, проверяющий, выполняется ли процесс в данный момент, Вам нужно лишь вызвать функцию, которая просит операционную систему проверить значение булевой переменной, принадлежащей объекту ядра «процесс». Тут нет ничего сложного. Вы можете также сообщить системе, чтобы та перевела Ваш поток в состояние ожидания и автоматически пробудила его при изменении значения булевой переменной с FALSE на TRUE. Тогда появляется возможность заставить поток в родительском процессе, ожидающий завершения дочернего процесса, просто заснуть до освобождения объекта ядра, идентифицирующего дочерний процесс. В дальнейшем Вы увидите, что в Windows есть ряд функций, позволяющих легко решать эту задачу. Я только что описал правила, определенные Microsoft для объекта ядра «процесс». Точно такие же правила распространяются и на объекты ядра «поток». Они тоже сразу после создания находятся в занятом состоянии. Когда поток завершается, операционная система автоматически переводит объект ядра «поток» в свободное состояние. Таким образом, используя те же приемы, Вы можете определить, выполняется ли в данный момент тот или иной поток. Как и объект ядра «процесс», объект ядра «поток» никогда не возвращается в занятое состояние.

Ожидаемые таймеры (waitable timers) — это объекты ядра, которые самостоятельно переходят в свободное состояние в определенное время или через регулярные промежутки времени. Чтобы создать ожидаемый таймер, достаточно вызвать функцию CreateWaitableTimer:

HANDLE CreateWaitableTimer(PSECURITY_ATTRIBUTES psa, BOOL fManualReset, PCTSTR pszName);

О параметрах psa и pszName я уже рассказывал в главе 3. Разумеется, любой процесс может получить свой («процессо зависимый») описатель существующего объекта «ожидаемый таймер», вызвав OpenWaitableTimer:

HANDLE OpenWaitableTimer(DWORD dwDesiredAccess, BOOL bInheritHandle, PCTSTR pszName);

По аналогии с событиями параметр fManualReset определяет тип ожидаемого таймера: со сбросом вручную или с автосбросом. Когда освобождается таймер со сбросом вручную, возобновляется выполнение всех потоков, ожидавших этот объект, а когда в свободное состояние переходит таймер с автосбросом — лишь одного из потоков.

Объекты «ожидаемый таймер» всегда создаются в занятом состоянии. Чтобы сообщить таймеру, в какой момент он должен перейти в свободное состояние, вызовите функцию SetWaitableTimer:

BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER *pDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, PVOID pvArgToCompletionRoutine, BOOL fResume);

Эта функция принимает несколько параметров, в которых легко запутаться. Очевидно, что hTimer определяет нужный таймер. Следующие два параметра (pDueTime и lPeriod) используются совместно: первый из них задает, когда таймер должен сработать в первый раз, второй определяет, насколько часто это должно происходить в дальнейшем.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]