Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Синтаксис и семантика основных объектов синхронизации.



Поток в роли объекта синхронизации.

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

Как уже было отмечено, потоки создаются только внутри процессов. Если, допустим, первичный поток процесса создает второй поток и затем сразу вызывает функцию WaitForSingleObject(), указав ей в качестве параметра, идентификатор созданного потока, родительский поток (в нашем случае первичный поток) будет переведен операционной системой в состояние ожидания. Родительский поток будет находиться в состоянии ожидания до тех пор, пока созданный им дочерний поток не завершит свою работу.

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

 

Синхронизация потоков с помощью объекта синхронизации «событие».

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

Рассмотрим, какие функции предоставляет операционная система для работы с объектом «событие».

Чтобы использовать этот объект в целях синхронизации его необходимо в начале создать. Для этого существует функция CreateEvent(). Выделим в этой функции следующие параметры:

- флаг ручного сброса (позволяет выбрать один из двух режимов объекта «событие»: ручной или автоматический;

- флаг начального состояния события (событие может быть создано в отмеченном либо неотмеченном состоянии);

- адрес имени объекта события (для синхронизации потоков, принадлежащих разным процессам).

 Для установки объекта «событие» в свободное состояние операционная система предоставляет функцию SetEvent(), а для переключения в занятое состояние – функцию ResetEvent().Эти переключения можно выполнять в произвольных точках программы. В качестве параметра этих функций используется идентификатор события.

Если при создании события выбран ручной режим, то событие нужно сбрасывать (устанавливать в неотмеченное состояние) вручную при помощи функции ResetEvent(). Если при создании события выбран автоматический режим, то событие будет сброшено (переведено в неотмеченное состояние) автоматически сразу после того, как задача завершит ожидание этого события.

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

Рассмотрим примерную схему использования «событий».

Некоторый поток создает объект «событие», вызывая функцию CreateEvent(). Событие может иметь имя, доступное всем потокам активных процессов. В процессе создания или позже соответствующей функцией поток устанавливает событие в определенное состояние (допустим, в неотмеченное состояние). Далее, вызывая функцию WaitForSingleObject(), поток может выполнять ожидание момента, когда событие перейдет в отмеченное состояние.

Другой поток, в общем случае принадлежащий другому процессу, может получить идентификатор события по его имени с помощью функции OpenEvent(). Далее, пользуюсь функциями SetEvent() или ResetEvent() этот поток может изменить состояние объекта «событие».

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

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

Критические секции и защита данных.

Часто бывает необходимо организовать последовательный доступ к ресурсам. Средством синхронизации потоков для обеспечения последовательного доступа к ресурсам являются критические секции. Особенность критических секций – это возможность их использования для синхронизации потоков одного процесса. Для обеспечения поочередного доступа к общим данным потоков разных процессов используются объекты «мьютексы».

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

EnterCriticajSection() - вход в критическую секцию

LeaveCriticalSection() – выход из критической секции

Все потоки, для которых организуется последовательный доступ к данным, должны вызвать функции EnterCriticajSection() и LeaveCriticalSection().

Это основные операции, выполняемые задачами (потоками) над критическими секциями.

Для использования в программе критических секций следует вначале объявить глобальную структурную переменную типа CRITICAL_SECTION, определенную в файле windows.h. Эта переменная носит организационный характер, с ее помощью операционная система Windows определяет, можно ли в данный момент предоставит доступ к общим данным тому или иному потоку. В первичном потоке программы (до создания дочерних потоков) необходимо выполнить инициализацию объекта «критическая секция». Инициализация выполняется при помощи функции InitialCriticalSection(). Все перечисленные функции, предназначенные для работы с критической секцией, имеют один параметр – адрес структурной переменной типа CRITICAL_SECTION.

Рассмотрим, как работают критические секции.

Если первый поток вошел в критическую секцию (фрагмент программы между функциями EnterCriticajSection() и LeaveCriticalSection()), но еще не вышел из него, то при попытке второго потока войти в ту же самую критическую секцию он будет переведен в состояние ожидания. Второй поток пробудет в состоянии ожидания до тех пор, пока первый не выйдет из критической секции.

Семафоры.

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

 Рассмотрим, как работает семафор.

Объект синхронизации «семафор» может находиться в отмеченном и неотмеченном состоянии. Поток, выдавшей функцию WaitForSingleObject() для семафора будет переведен операционной системой в состояние ожидания, если семафор находился в неотмеченном состоянии. С каждым семафором связывается счетчик (определяет предельное количество потоков для одновременной работы с семафором). Если значение счетчика семафора равно нулю, то состояние семафора считается неотмеченным. Выдача функции WaitForSingleObject() понижает значение счетчика семафора на единицу. Если поток выдал функцию WaitForSingleObject() при значении счетчика семафора, равным нулю, то поток будет переведен в состояние ожидания. Таким образом, пока значение счетчика семафора больше нуля, очередной поток, выдавший WaitForSingleObject(), получит доступ к ресурсу, связанным с семафором.

Функции, предоставляемые операционной системой для работы с семафором.

- CreateSemaphore() - создание семафора. Основными параметрами функции являются значение счетчика семафора и адрес строки с именем семафора.

- RealeaseSemaphore() - увеличение значения счетчика семафора.

- OpenSemaphore() – открывание семафора. Основной параметр – адрес строки с именем семафора. Используется в случае синхронизации потоков разных процессов.

Вопросы для самопроверки

1. Поясните необходимость синхронизации в современных вычислительных системах.

2. Какие объекты синхронизации Вам известны.

3. Перечислите состояния объектов синхронизации.

4. Роль счетчика в идеологии работы объекта синхронизации «семафор».

ГЛОССАРИЙ

ФЛАГ – Признак, имеющий два значения (1/0) и занимающий один двоичный разряд


Поделиться:



Последнее изменение этой страницы: 2019-03-22; Просмотров: 301; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.017 с.)
Главная | Случайная страница | Обратная связь