Синхронизация потоков с использованием объектов ядра
Лабораторная работа № 3
1. ЦЕЛЬ РАБОТЫ
Изучение принципов использования объектов синхронизации режима ядра для обеспечения монопольного доступа потоков к разделяемым ресурсам, приобретение практических навыков использования средств API Windows для создания многопоточных[ приложений.
2. СИНХРОНИЗИРУЮЩИЕ ОБЪЕКТЫ РЕЖИМА ЯДРА
Критические секции (см. л.р. №2) не являются объектами ядра, поэтому их можно использовать для синхронизации доступа к разделяемым ресурсам лишь в рамках одного процесса.
Синхронизирующие объекты ядра принципиально доступны потокам любых процессов. Единственный их недостаток — меньшее быстродействие, поскольку для работы с ними поток должен перейти из пользовательского режима в режим ядра, на что требуется около 1000 процессорных тактов.
Следующие объекты ядра используются для синхронизации доступа любых потоков к разделяемым ресурсам:
· мьютексы
· события
· семафоры
Эти объекты, подобно критической секции, «охраняют» вход в некоторый участок кода и бывают в свободном или занятом состоянии. Последнее означает, что их «захватил» некоторый поток, и другие потоки, желающие войти в свой кодовый участок, «охраняемый» данным объектом, должны ждать его освобождения.
Потоки не получают процессорного времени, пока ожидаемые ими объекты заняты.
Как только объект освободится, операционная система переводит ждущие потоки в разряд планируемых.
Потоки обычно «усыпляют себя» до освобождения синхронизирующего объекта с помощью функции:
DWORD WaitForSingleObject(HANDLE hObject, DWORD dwTimeOut);
где hObject –дескриптор объекта, dwMilliseconds указывает, сколько времени (в миллисекундах) поток готов ждать освобождения объекта.
В качестве значения параметра dwTimeOut используют три варианта:
dwTimeOut |
Действия |
0 |
Функция только проверяет состояние объекта (занят или свободен) и сразу же возвращается |
Число МСек |
Функция ожидает освобождения объекта не более указанного времени |
INFINITE |
Время ожидания бесконечно. Если объект так и не освободится, поток никогда не получит процессорного времени |
Функция WaitForSingleObject может возвращать одно из следующих значений:
Возвращаемое значение |
Описание |
WAIT_TIMEOUT |
Объект не перешел в свободное состояние, но интервал времени истек |
WAIT_ABANDONED |
Ожидаемый объект является мьютексом, который не был освобожден владеющим им потоком перед окончанием этого потока. Объект мьютекс автоматически переведен системой в свободное состояние. |
WAIT_OBJECT_0 |
Объект перешел в свободное состояние |
WAIT_FAILED |
Произошла ошибка, причину которой можно узнать, вызвав GetLastError |
Вот пример ожидания освобождения некоторого обобщенного объекта с дескриптором hObject:
DWORD dw = WaitForSlngleObject(hObject, 5000);
switch (dw)
{
case WAIT_OBJECT_0: // объектсвободен
break;
case WAIT_TIMEOUT: // объект не
освободился в течение 5000 мс
break;
case WAIT_FAILED: // некорректный
вызов функции
break;
}
Объекты ядра «мьютексы» гарантируют любым потокам монопольный доступ к разделяемому ресурсу и ведут себя точно так же, как и критические секции. Мьютекс позволяет синхронизировать доступ к ресурсу для потоков из разных процессов; при этом можно задать максимальное время ожидания доступа к ресурсу.
Для использования объекта-мьютекса один из процессов должен сначала создать его вызовом функции:
HANDLE CreateMutex(
PSECURITY_ATTRIBUTES psa,
BOOL fInitialOwner,
PCTSTR pszName
);
Параметр psaобычно равен NULL.
Параметр fInitialOwnerопределяет начальное состояние мъютекса. Если в нем передается false (что обычно и бывает), мьютекс изначально не захвачен никаким потоком и находится в свободном состоянии. Если же в нем передается true, мьютекс считается захваченным потоком, создавшим его.
Параметр pszName – имя мьютекса (char-строка), возможно пустое.
Функция возвращает дескриптор мьютекса, который имеет смысл только в данном процессе.
Любой другой процесс может получить свой «процессо-зависимый» дескриптор существующего объекта «мьютекс», вызвав OpenMutex:
HANDLE OpenMutex( DWORD fdwAccess, BOOL bInheritHandle, PCTSTR pszName);
Чтобы это выполнить, нужно знать имя мьютекса, которое просвоено ему при создании.
Поток получает доступ к разделяемому ресурсу, вызывая функцию WaitForSingleObject и передавая ей дескриптор мьютекса, который охраняет этот ресурс. Если функция определяет, что мьютекс занят, вызывающий поток переводится в состояние ожидания.
Когда ожидание мьютекса потоком успешно завершается, последний получает монопольный доступ к защищенному ресурсу. Все остальные потоки, пытающиеся обратиться к этому ресурсу, переходят в состояние ожидания.
Когда поток, занимающий ресурс, заканчивает с ним работать, он должен освободить мьютекс вызовом функции
BOOL ReleaseMutex(HANDLE hMutex);
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.