Краткие теоретические сведения. В многозадачной (многопоточной) среде возникает проблема одновре­мен­ного доступа к одним и тем же ресурсам (данным) со стороны нескольких потоков

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

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

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

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

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

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

Простейшее средство исключения в Windows — объект CriticalSection. Он представляет собой обычную структуру и не имеет глобальной идентификации, поэтому может использоваться только потоками одного процесса. Использование CriticalSection выглядит в общем случае следующим образом:

CRITICAL_SECTION cs;

InitializeCriticalSection(&cs);

EnterCriticalSection(&cs);

… //защищенная критическая секция

LeaveCriticalSection(&cs);

DeleteCriticalSection(&cs);

Вызов EnterCriticalSection — попытка входа в критическую секцию. Поток блокируется, если секция уже занята другим потоком, до момента ее освобождения. Повторное вхождение в критическую секцию допускается толь­ко для одного и того же потока, что помогает избегать самоблокировок. Блокировка управляется счетчиком, каждое вхождение в секцию увеличивает счетчик, освобождение — уменьшает, поэтому их количество должно быть сбаланси­ровано.

Для синхронизации потоков разных процессов предусмотрены специи­альные объекты — Event, Mutex, Semaphore, WaitableTimer. Все они являются именованными и допускают глобальную идентификацию по именам.

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

Объект «событие» (Event) — наиболее простая разновидность. Объекты создается функцией CreateEvent() и бывают двух типов — «ручные» и «авто­матические». Открытие существующего объекта «событие» по его имени — OpenEvent(). Установка события (перевод в состояние signaled) происходит всегда явно, функцией SetEvent(), сброс — для «ручных» событий явно, функцией ResetEvent(), для «автоматических» — автоматически при выполне­нии Wait-функции. Также имеется функция PulseEvent() — временная установ­ка события, активизация всех ожидавших его потоков и автоматический сброс. Кроме того, объекты Event ассоциируются с файлами при организации асинхронного ввода-вывода.

Объект «мьютекс» (Mutex) — простейший двузначный семафор для организации критических секций. Принято считать, что он «захватывается» потоком, и если мьютекс в этот момент уже занят, очередной захватывающий его поток блокируется. Подобно CriticalSection, Mutex допускает повторный захват его одним и тем же потоком. Создание мьютекса — функция CreateMutex(), открытие существующего по имени — OpenMutex(), осво­бождение — ReleaseMutex(), захват с возможной блокировкой — Wait-функции.

Объект «семафор» (Semaphore) — отличается от мьютекса тем, что является счетчиком и может принимать множество значений от 0 и выше. «Занятым» считается семафор с нулевым значением, с ненулевым — свобод­ным. При попытке опустить значение ниже нуля происходит блокировка. Работа семафора не зависит от того, разные потоки обращаются к нему или один и тот же. Создание семафора — функция CreateSemaphore(), открытие существующего по имени — OpenSemaphore(), «подъём» счетчика (разблоки­рование) — ReleaseSemaphore(), проверка и «опускание», в том числе блоки­рование — Wait-функции.

Кроме специализированных объектов синхронизации, Wait-функции могут работать также и с другими объектами, например:

– процессы и потоки — ожидание завершения;

– файлы — ожидание окончания текущей операции, и так далее.

Контрольные вопросы

1) Что такое синхронизация доступа к ресурсам и зачем она нужна.

2) Какие существуют объекты синхронизации.

3) Объект синхронизации Event, его создание, уничтожение и использование. Параметры данных функций.

4) Что такое автоматический сброс Event-а.

5) Функция WaitForSingleObject, ее параметры и возвращаемые значения. Использование данной функции.

6) Объект синхронизации CriticalSection, его использование.

7) Отличие объекта синхронизации CriticalSection от объекта синхронизации Event.

8) Объект синхронизации Mutex, его создание, уничтожение и использование. Параметры данных функций.

9) Объект синхронизации Semaphore, его создание, уничтожение и использование. Параметры данных функций. Особенности данного объекта синхронизации.

Варианты заданий

В каждом из заданий необходимо создать несколько потоков и защищенный ресурс. Каждый из потоков должен делать следующее: проверить, свободен ли защищенный ресурс; если он занят, то дождаться освобождения; если он свободен, то занять его, выполнить какие-то действия (указанные в задании), сделать паузу на одну секунду и освободить ресурс. Если в задании указано два объекта синхронизации, то необходимо выполнить отдельную программу для каждого из них.

1. Каждый из трех потоков должен пытаться закрасить главное окно в свой цвет: первый — в синий, второй — в красный и третий — в зеленый. В результате каждую секунду цвет фона главного окна будет изменяться. Реализовать синхронизацию доступа к ресурсам через Event, а затем через CriticalSection.

2. Каждый из трех потоков должен пытаться закрасить главное окно в свой цвет: первый — в желтый, второй — в голубой и третий — в черный. В результате каждую секунду цвет фона главного окна будет изменяться. Реализовать синхронизацию доступа к ресурсам через Mutex, а затем через Semaphore.

3. На главном окне необходимо создать Edit. Каждый из трех потоков должен пытаться установить в данный Edit соответствующий текст: First, Second или Third. Реализовать синхронизацию доступа к ресурсам через Event, а затем через CriticalSection.

4. На главном окне необходимо создать Edit. Каждый из трех потоков должен пытаться установить в данный Edit соответствующий текст: String1, String2, String3. Реализовать синхронизацию доступа к ресурсам через Mutex, а затем через Semaphore.

5. На главном окне необходимо нарисовать движущуюся справа налево фигуру (например, квадрат). Также необходимо создать два потока: первый из них будет опускать фигуру вниз, а второй поднимать вверх. Реализовать синхронизацию доступа к ресурсам через Event, а затем через CriticalSection.

6. На главном окне необходимо нарисовать движущуюся сверху вниз фигуру. Также необходимо создать два потока: первый из них будет смещать фигуру влево, а второй вправо. Реализовать синхронизацию доступа к ресурсам через Mutex, а затем через Semaphore.

7. Создать четыре потока, каждый из которых будет пытаться вывести в центре окна свой текст: AAAAA, BBBB, CCCCC, DDDDDD. Реализовать синхронизацию доступа к выводу на окно через Event, а затем через CriticalSection.

8. Создать четыре потока, каждый из которых будет пытаться вывести в центре окна свой текст: XXXX, ZZZZZ, TTT, YYYY. Реализовать синхронизацию доступа к выводу на окно через Mutex, а затем через Semaphore.

9. Создать три потока, каждый из которых будет пытаться вывести в центре окна свой рисунок: звездочку, квадратик, закрашенный эллипс. Реализовать синхронизацию доступа к выводу на окно через Event, а затем через CriticalSection.

10. Создать три потока, каждый из которых будет пытаться вывести в центре окна свой рисунок: домик, дерево, ромбик. Реализовать синхронизацию доступа к выводу на окно через Mutex, а затем через Semaphore.

11. Создать на окне элемент управления ListBox. Также создать два потока, каждый из которых будет добавлять в данный ListBox свой текст: First или Second. Реализовать синхронизацию доступа к ListBox через Event, а затем через CriticalSection.

12. Создать на окне элемент управления ListBox. Также создать два потока, каждый из которых будет добавлять в данный ListBox свой текст: First или Second. Реализовать синхронизацию доступа к ListBox через Mutex, а затем через Semaphore.

13. Создать три потока, каждый из которых будет двигать по окну слева направо паровозик. В каждый момент доступ к выводу на окно должен иметь только один поток. Реализовать синхронизацию доступа к выводу на окно через Event, а затем через CriticalSection.

14. Создать пять потоков, каждый из которых будет двигать по окну слева направо паровозик. В каждый момент доступ к выводу на окно должны иметь два потока. Реализовать синхронизацию доступа к выводу на окно через Semaphore.

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

Лабораторная работа 13:
Приоритеты


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: