Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Crytical Sections
В составе API ОС Windows имеются специальные и эффективные функции для организации входа в критическую секцию и выхода из нее потоков одного процесса в режиме пользователя. Они называются EnterCriticalSection и LeaveCriticalSection и имеют в качестве параметра предварительно проинициализированную структуру типа CRITICAL_SECTION. Примерная схема программы может выглядеть следующим образом. CRITICAL_SECTION cs; DWORD WINAPI SecondThread() { InitializeCriticalSection(& cs); EnterCriticalSection(& cs); … критический участок кода LeaveCriticalSection(& cs); } main () { InitializeCriticalSection(& cs); CreateThread(NULL, 0, SecondThread, …); EnterCriticalSection(& cs); … критический участок кода LeaveCriticalSecLion(& cs); DeleteCriticalSection(& cs); } Функции EnterCriticalSection и LeaveCriticalSection реализованы на основе Interlocked-функций, выполняются атомарным образом и работают очень быстро. Существенным является то, что в случае невозможности входа в критический участок поток переходит в состояние ожидания. Впоследствии, когда такая возможность появится, поток будет " разбужен" и сможет сделать попытку входа в критическую секцию. Механизм пробуждения потока реализован с помощью объекта ядра " событие" (event), которое создается только в случае возникновения конфликтной ситуации. Пример организации синхронизации: Задача о кольцевом буфере. Потоки производители и потребители разделяют кольцевой буфер, состоящий из 100 ячеек (целочисленный массив на 100 элементов). Производители передают сообщения потребителям, помещая его в конец очереди буфера. Потребители сообщение извлекают из начала очереди буфера. Создать многопоточное приложение с потоками писателями и читателями. Предотвратить такие ситуации как, изъятие сообщения из пустой очереди или помещения сообщения в полный буфер. При решении задачи использовать семафоры. Обсуждение. Пусть для определенности буфер - это целочисленный массив из 100 элементов. Задача обладает двумя критическими секциями. Первая критическая секция связана с операциями чтения-записи нескольких потоков в общий буфер. Вторая критическая секция определяется тем. что буфер являются конечным, запись должна производиться только в те ячейки, которые являются свободными или уже прочитаны потоками-читателями (условная взаимная синхронизация). Для защиты первой критической секции воспользуемся двумя двоичными семафорами (мьютексами). Один двоичный семафор сделает возможным запись в буфер только для одного потока-писателя. Второй двоичный семафор сделает возможным чтение из буфера только для одного потока-читателя. Операция чтения должна быть защищена, потому что она является и операцией записи тоже, так как поток, прочитавший ячейку буфера, обязан ее как-то пометить. Иначе через определенное время выполнения программы, операция записи может стать невозможной или некорректной, в силу того, что буфер конечен. Операции чтения и записи могут проходить параллельно, так как всегда происходят в разных ячейках. Для условной синхронизации воспользуемся двумя семафорами. Значение первого семафора показывает, сколько ячеек в буфере свободно. Ячейка свободна, когда в нее еще не осуществлялась запись или ячейка быта прочитана. Значение второго семафора показывает, сколько ячеек в буфере занято. Естественно, операция записи не может быть выполнена, пока количество занятых ячеек равно 100 (или количество свободных ячеек равно 0), и операция чтения не может быть выполнена, пока количество свободных ячеек равно 100 (или количество занятых ячеек равно 0). Для блокировки потока воспользуемся: условиями, заключенными в скобки, исходя из особенностей поведения семафоров.
#include < stdio.h> #include< stdlib.h> #include < conio.h> #include< windows.h> const int n=100, //длина буфера m=7, //количество производителей k=3; //количество потребителей int buf[n], front=0, rear=0; HANDLE hSemFull, hSemEmpty, //семафоры для условной синхронизации hMutexD, hMutexF; //мьютексы для исключительного доступа
|