Главная страница
Навигация по странице:

  • 2. Общие сведения

  • Работа с объектами синхронизации

  • Взаимоисключения

  • Критические секции

  • Защищенный доступ к переменным

  • Cинхронизация в MFC

  • Конечный результат

  • (ЛР4)_Объекты_синхр_коротк. Лабораторная работа 4 Объекты синхронизации Windows


    Скачать 24.43 Kb.
    НазваниеЛабораторная работа 4 Объекты синхронизации Windows
    Дата06.04.2022
    Размер24.43 Kb.
    Формат файлаdocx
    Имя файла(ЛР4)_Объекты_синхр_коротк.docx
    ТипЛабораторная работа
    #446575


    Лабораторная работа № 4

    Объекты синхронизации Windows

    1. Цель работы

    Целью лабораторной работы является получение практических навыков синхронизации процессов многопоточных приложений в Windows.

    2. Общие сведения

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

    - взаимоисключение (mutex),

    - критическая секция (critical section),

    - событие (event),

    - семафор (semaphore).

    Каждый из них реализует свой механизм синхронизации, который используется в конкретных случаях. Объектами синхронизации могут выступать и сами процессы и потоки (если они честно ожидают завершения другого потока или процесса), файлы, коммуникационные устройства, консольный ввод и уведомления об изменении.
    Каждый объект синхронизации может находиться в так называемом сигнальном состоянии. Для каждого типа объектов это состояние имеет различный смысл. Потоки могут проверять текущее состояние объекта и/или ждать изменения этого состояния и таким образом согласовывать свои действия. Очень важно, что когда поток работает с объектами синхронизации (создает их, изменяет состояние) система гарантированно не прервет его выполнения, пока он не завершит это действие. Таким образом, все конечные операции с объектами синхронизации являются атомарными (неделимыми).
    Реальной связи объектов синхронизации с ресурсами, конечно, нет. Они не предотвращают доступ к ресурсу, а только сообщают о возможности работы с ресурсом или необходимости ожидания доступа к нему.
    (Help Windows:) Критические секции обеспечивают синхронизацию, аналогичную той, которую дают и мьютексы, за исключением того, что критическая секция может использоваться только потоками одного процесса. События, мьютексы и семафоры также могут использоваться в однопроцессном приложении, но критическая секция работает несколько быстрее и эффективнее при взаимоисключающей синхронизации. Подобно мьютексу, критической секцией в каждый момент времени может владеть только один поток, что делает ее полезной для защиты разделяемого ресурса от одновременного доступа. Например, процесс может использовать критическую секцию, чтобы избежать одновременной модификации глобальной структуры данных более, чем одним потоком.
    Работа с объектами синхронизации

    Чтобы создать тот или иной объект синхронизации, производится вызов специальной функции WinAPI типа Create... (напр. CreateMutex). Этот вызов возвращает дескриптор объекта (HANDLE), который может использоваться всеми потоками, принадлежащими данному процессу. Есть возможность получить доступ к объекту синхронизации из другого процесса - либо унаследовав дескриптор этого объекта, либо, что предпочтительнее, воспользовавшись вызовом функции открытия объекта (Open...). После этого вызова процесс получит дескриптор, который в дальнейшем можно использовать для работы с объектом. Объекту, если только он не предназначен для использования внутри одного процесса, обязательно присваивается имя. Имена всех объектов должны быть различны (даже если они разного типа). Нельзя, например, создать событие и семафор с одним и тем же именем.
    По имеющемуся дескриптору объекта можно определить его текущее состояние. Это делается с помощью т.н. ожидающих функций. Чаще всего используется функция WaitForSingleObject. Эта функция принимает два параметра, первый из которых - дескриптор объекта, второй - время ожидания в мсек. Функция возвращает WAIT_OBJECT_0, если объект находится в сигнальном состоянии, WAIT_TIMEOUT - если истекло время ожидания, и WAIT_ABANDONED, если объект-взаимоисключение не был освобожден до того, как владеющий им поток завершился. Если время ожидания указано равным нулю, функция возвращает результат немедленно, в противном случае она ждет в течение указанного промежутка времени. В случае, если состояние объекта станет сигнальным до истечения этого времени, функция вернет WAIT_OBJECT_0, в противном случае функция вернет WAIT_TIMEOUT.

    Если в качестве времени указана символическая константа INFINITE, то функция будет ждать неограниченно долго, пока состояние объекта не станет сигнальным.

    Если необходимо узнавать о состоянии сразу нескольких объектов, следует воспользоваться функцией WaitForMultipleObjects.

    Чтобы закончить работу с объектом и освободить дескриптор вызывается функция CloseHandle.

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

    Объекты-взаимоисключения (мьютексы, mutex - от MUTual EXclusion) позволяют координировать взаимное исключение доступа к разделяемому ресурсу. Сигнальное состояние объекта (т.е. состояние "установлен") соответствует моменту времени, когда объект не принадлежит ни одному потоку и его можно "захватить". И наоборот, состояние "сброшен" (не сигнальное) соответствует моменту, когда какой-либо поток уже владеет этим объектом. Доступ к объекту разрешается, когда поток, владеющий объектом, освободит его.
    Для того, чтобы объявить взаимоисключение принадлежащим текущему потоку, надо вызвать одну из ожидающих функций. Поток, которому принадлежит объект, может его "захватывать" повторно сколько угодно раз (это не приведет к самоблокировке), но столько же раз он должен будет его освобождать с помощью функции ReleaseMutex.
    События

    Объекты-события используются для уведомления ожидающих потоков о наступлении какого-либо события. Различают два вида событий - с ручным и автоматическим сбросом. Ручной сброс осуществляется функцией ResetEvent. События с ручным сбросом используются для уведомления сразу нескольких потоков. При использовании события с автосбросом уведомление получит и продолжит свое выполнение только один ожидающий поток, остальные будут ожидать дальше.
    Функция CreateEvent создает объект-событие, SetEvent - устанавливает событие в сигнальное состояние, ResetEvent-сбрасывает событие. Функция PulseEvent устанавливает событие, а после возобновления ожидающих это событие потоков (всех при ручном сбросе и только одного при автоматическом), сбрасывает его. Если ожидающих потоков нет, PulseEvent просто сбрасывает событие.
    Семафоры

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

    Объект-критическая секция помогает программисту выделить участок кода, где поток получает доступ к разделяемому ресурсу, и предотвратить одновременное использование ресурса. Перед использованием ресурса поток входит в критическую секцию (вызывает функцию EnterCriticalSection). Если после этого какой-либо другой поток попытается войти в ту же самую критическую секцию, его выполнение приостановится, пока первый поток не покинет секцию с помощью вызова LeaveCriticalSection. Похоже на взаимоисключение, но используется только для потоков одного процесса.
    Существует также функция TryEnterCriticalSection, которая проверяет, занята ли критическая секция в данный момент. С ее помощью поток в процессе ожидания доступа к ресурсу может не блокироваться, а выполнять какие-то полезные действия.
    Защищенный доступ к переменным

    Существует ряд функций, позволяющих работать с глобальными переменными из всех потоков не заботясь о синхронизации, т.к. эти функции сами за ней следят. Это функции InterlockedIncrement/InterlockedDecrement, InterlockedExchange, InterlockedExchangeAdd и InterlockedCompareExchange. Например, функция InterlockedIncrement увеличивает значение 32-битной переменной на единицу - удобно использовать для различных счетчиков. Более подробно об этих функциях см. в документации.
    Cинхронизация в MFC

    Библиотека MFC содержит специальные классы для синхронизации потоков (CMutex, CEvent, CCriticalSection и CSemaphore). Эти классы соответствуют объектам синхронизации WinAPI и являются производными от класса CSyncObject. Чтобы понять, как их использовать, достаточно просто взглянуть на конструкторы и методы этих классов - Lock и Unlock. Фактически эти классы - всего лишь обертки для объектов синхронизации.
    Eсть еще один способ использования этих классов - написание так называемых потоково-безопасных классов (thread-safe classes). Потоково-безопасный класс - это класс, представляющий какой либо ресурс в вашей программе. Вся работа с ресурсом осуществляется только через этот класс, который содержит все необходимые для этого методы. Причем класс спроектирован таким образом, что его методы сами заботятся о синхронизации, так что в приложении он используется как обычный класс. Объект синхронизации MFC добавляется в этот класс в качестве закрытого члена класса, и все функции этого класса, осуществляющие доступ к ресурсу, согласуют с ним свою работу.
    С классами синхронизации MFC можно работать как напрямую, используя методы Lock и Unlock, так и через промежуточные классы CSingleLock и CMultiLock (хотя на мой взгляд, работать через промежуточные классы несколько неудобно. Но использование класса СMultiLock необходимо, если вы хотите следить за состоянием сразу нескольких объектов).

    Не используя возможности многозадачности, которые предоставляет Windows, программы теряют преимущества этой ОС.
    Требования:

    1. Использование только вызовов API

    2. Желательно описание внешних вызовов ОС производить непосредственно в своем коде (разрешено пользоваться описанием windows.pas)

    3. Обработка ошибок и их анализ по каждому вызову функций API

    4. Остановка исследуемого процесса по вводу символа «q» с клавиатуры

    Конечный результат:

    1. Получить требуемую в варианте величину.

    2. Пакетный файл компиляции.

    3. Отчет с выводами и анализом результатов. В анализ должны входить оценки вероятностных показателей измеренной в варианте величины.

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

    5. Исходный код программы на дискете.


    Варианты:

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

    2. Реализовать критическую секцию на основе объекта синхронизации типа «событие». Продемонстрировать функционирование на примере защиты реализованной критической секцией некоторой очереди сообщений произвольного формата.

    3. Отобразить файл размера 32К в память. Реализовать транспортировку данных из отображения в файл на диске (один поток). Два других потока записывают некоторые данные в это отображение. Синхронизация доступа к данным отображения осуществляется при помощи объекта синхронизации типа «мьютекс».

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

    5. Реализовать моделирование «тупика» на примере работы с критическими секциями. Временные параметры модели определяются до начала моделирования (произвольны, но обязательно изменяемы). Провести анализ вероятности тупика, если она равна 1, то обосновать.

    6. Реализовать моделирование «гонок» на примере работы с критическими секциями. Временные параметры модели определяются до начала моделирования (произвольны, но обязательно изменяемы). Провести анализ вероятности тупика, если она равна 1, то обосновать.

    7. (со звездочкой) Реализовать моделирование «столкновений» на примере работы с критическими секциями. Временные параметры модели определяются до начала моделирования (произвольны, но обязательно изменяемы). Провести анализ вероятности тупика, если она равна 1, то обосновать.

    8. Реализовать мьютекс на основе объекта синхронизации «событие». Количественные характеристики мьютекс должны быть аналогичны соответствующему объекту ядра типа мьютекс.

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

    10. Реализовать на мьютексе семафор. Количественные характеристики семафора должны быть аналогичны соответствующему объекту ядра типа семафор.


    написать администратору сайта