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

Лабораторная работа №6 «Специальные объекты синхронизации»

Краткие теоретические сведенья:

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

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

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

DWORD WaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds);

где hObject - описатель ожидаемого объекта ядра, а второй параметр - максимальное время ожидания объекта.

Поток создает объект ядра при помощи семейства функций Create (CreateSemaphore, CreateThread и т.д.), после чего объект посредством описателя становится доступным всем потокам данного процесса. Копия описателя может быть получена при помощи функции DuplicateHandle и передана другому процессу, после чего потоки смогут воспользоваться этим объектом для синхронизации.

Перейдем к рассмотрению объектов ядра, которые предназначены специально для синхронизации. Это события, семафоры и мьютексы.

Кратко рассмотрим каждый из них:

Событие (event)

Пожалуй, самый простой и фундаментальный синхронизирующий объект. Это всего лишь флаг, которому функциями SetEvent/ResetEventможно задать состояние: сигнализирующее или нейтральное.Событие– это самый удобный способ передать сигнал ожидающему потоку, что некое событие свершилось (потому оно так и называется), и можно продолжать работу. С помощью события легко решить проблему синхронизации при инициализации рабочего потока:

// для простоты описатель события будет храниться в глобальной переменной:

HANDLE g_hEventInitComplete = NULL; // никогда не оставляем переменную неинициализированной!

{ // код в главном потоке

// создание события

g_hEventInitComplete = ::CreateEvent( NULL,

FALSE,

FALSE, // начальное состояние - нейтральное

NULL );

if( !g_hEventInitComplete ) { /* обработка ошибок */ }

// создание рабочего потока

DWORD idWorkerThread = 0;

HANDLE hWorkerThread = ::CreateThread( NULL, 0, &WorkerThreadProc, NULL, 0, &idWorkerThread );

if( !hWorkerThread ) { /* обработка ошибки */ }

// ожидание сигнала от рабочего потока

DWORD dwWaitResult = ::WaitForSingleObject( g_hEventInitComplete, INFINITE );

if( dwWaitResult != WAIT_OBJECT_0 ) { /* ошибка */ }

// рабочий поток завершил инициализацию.

VERIFY( ::CloseHandle( g_hEventInitComplete ) ); // закрытие ненужных объектов

g_hEventInitComplete = NULL;

}

// функция рабочего потока

DWORD WINAPI WorkerThreadProc( LPVOID _parameter )

{

InitializeWorker(); // инициализация

// сигнализация, что инициализация завершена

BOOL isOk = ::SetEvent( g_hEventInitComplete );

if( !isOk ) { /* ошибка */ }

}

Надо заметить, что существуют две заметно отличающиеся разновидности событий. Мы можем выбрать одну из них с помощью второго параметра функции CreateEvent. Если он TRUE, создается событие, состояние которого управляется только вручную, то есть функциямиSetEvent/ResetEvent. Если же он FALSE, будет создано событие с автосбросом. Это означает, что как только некий поток, ожидающий данного события, будет освобожден сигналом от этого события, оно автоматически будет сброшено обратно в нейтральное состояние. Наиболее ярко их отличие проявляется в ситуации, когда одного события ожидают сразу несколько потоков. Событие с ручным управлением подобно стартовому пистолету. Как только оно будет установлено в сигнализирующее состояние, будут освобождены сразу все потоки. Событие же с автосбросом похоже на турникет в метро: оно отпустит лишь один поток и вернется в нейтральное состояние.