Средства межпроцессной синхронизации
Классификация средств обеспечивающих межпроцессное одновременное действие. Основные случаи, при которых потоки должны взаимодействовать друг с другом. Типы объектов, используемых для синхронизации, и функция ожидания. Порядок создания ожидаемого таймера.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | реферат |
Язык | русский |
Дата добавления | 13.10.2010 |
Размер файла | 55,8 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Средства межпроцессной синхронизации
1. Средства межпроцессного взаимодействия
Потребность в синхронизации потоков возникает только в мультипрограммной операционной системе и связана с совместным использованием аппаратных и информационных ресурсов вычислительной системы. Синхронизация необходима для исключения гонок и тупиков при обмене данными между потоками, разделении данных, при доступе к процессору и устройствам ввода-вывода.
Во многих операционных системах эти средства называются средствами межпроцессного взаимодействия -- Inter Process Communications (IPC), что отражает историческую первичность понятия "процесс" по отношению к понятию "поток".
Сначала появилась необходимость в общении процессов, выполняющихся на одном компьютере. В дальнейшем с бурным развитием сетевых технологий все острее стала чувствоваться потребность в средствах для взаимодействия процессов, выполняющихся на разных компьютерах в сети. Особенно трудна такая задача, если это компьютеры на базе разных платформ и/или с разными операционными системами.
Средств, обеспечивающих взаимодействие между процессами, создано достаточно много. Огромное их количество было реализовано в Windows 9x, еще больше - в Windows XP. Классифицировать их, в общем случае, можно на два вида (рис.1):
1. Средства межпроцессной синхронизации.
2. Средства межпроцессного обмена данными.
Многие из средств межпроцессного обмена данными выполняют также и функции синхронизации: в том случае, когда данные для процесса-получателя отсутствуют, последний переводится в состояние ожидания средствами ОС, а при поступлении данных от процесса-отправителя процесс-получатель активизируется.
Выполнение потока в мультипрограммной среде всегда имеет асинхронный характер. Очень сложно с полной определенностью сказать, на каком этапе выполнения будет находиться процесс в определенный момент времени.
Любое взаимодействие процессов или потоков связано с их синхронизацией, которая заключается в согласовании скоростей потоков путем приостановки потока до наступления некоторого события и последующей его активизации при наступлении этого события. Синхронизация лежит в основе любого взаимодействия потоков, связано ли это взаимодействие с разделением ресурсов или с обменом данными. При совместном использовании аппаратных ресурсов синхронизация также совершенно необходима.
Таким образом, потоки должны взаимодействовать друг с другом в двух основных случаях:
совместно используя разделяемый ресурс (чтобы не разрушить его);
когда нужно уведомлять другие потоки о завершении каких-либо операций.
Для синхронизации потоков прикладных программ программист может использовать, как собственные средства и приемы синхронизации, так и средства операционной системы.
Например, два потока одного прикладного процесса могут координировать свою работу с помощью доступной для них обоих глобальной логической переменной, которая устанавливается в единицу при осуществлении некоторого события, например выработки одним потоком данных, нужных для продолжения работы другого.
Однако во многих случаях более эффективными или даже единственно возможными являются средства синхронизации, предоставляемые операционной системой в форме системных вызовов. Так, потоки, принадлежащие разным процессам, не имеют возможности вмешиваться каким-либо образом в работу друг друга. Без посредничества операционной системы они не могут приостановить друг друга или оповестить о произошедшем событии. Средства синхронизации используются операционной системой не только для синхронизации прикладных процессов, но и для ее внутренних нужд.
Таким образом, для совместной работы потоков без разрушения памяти в интерфейсе Win API предоставляются объекты синхронизации. Объекты синхронизации обеспечивают доступ к системным ресурсам, которые могут находиться под управлением потоков одних и тех же либо других процессов.
Обычно для синхронизации используются шесть типов объектов (рис.1):
семафоры;
критические секции (разделы);
исключающие семафоры (объекты типа mutex);
события;
ожидающие таймеры;
блокирующие переменные.
Все объекты синхронизации отличаются друг от друга условием установки состояний.
Объект синхронизации обладает двумя состояниями:
сигнальным (signaled state);
несигнальным (non signaled state).
Когда объект синхронизации находится в состоянии занятости, или несигнальном состоянии, выполнение ожидающего потока НЕ может быть продолжено. А когда объект синхронизации оказывается в сигнальном состоянии, ожидающий поток может продолжить свое выполнение.
Функции ожидания представляют собой набор вызовов API, которые приостанавливают выполнение потоков до тех пор, пока не станет истинным заданный ряд условий. Функции ожидания проверяют сигнальное состояние объектов синхронизации.
Если указанный объект оказывается в сигнальном состоянии, функция ожидания завершается, а выполнение потока продолжается. В противном случае функция ожидания будет поддерживать поток в цикле, опрашивая состояние объекта синхронизации до тех пор, пока:
оно не станет сигнальным;
не истечет время ожидания.
2. Синхронизация потоков в исполнительной системе
Таймеры ожидания (waitable timers) - это объекты ядра, которые самостоятельно переходят в свободное состояние в определенное время или через регулярные промежутки времени. Чтобы создать ожидаемый таймер, достаточно вызвать функцию CreateWaitableTimer().
HANDLE CreateWaitableTimer( LPSECURITY_ATTRIBUTES lpTimerAttrib, BOOL fManualReset, LPCTSTR lpszName);
Параметры:
lpTimerAttrib - очевиден и отвечает за атрибуты доступа к таймеру.
fManualReset - определяет тип ожидаемого таймера: со сбросом вручную или с автосбросом. Когда освобождается таймер со сбросом вручную, возобновляется выполнение всех потоков, ожидавших этот объект, а когда в свободное состояние переходит таймер с автосбросом -- лишь одного из потоков.
pszName - передавая в нем NULL, создается безымянный (анонимный) объект ядра. В этом случае можно разделять объект между процессами либо через наследование, либо с помощью DuplicateHandle(). А чтобы разделять объект по имени, необходимо присвоить ему какое-нибудь имя. Тогда вместо NULL в параметре pszName нужно передать адрес строки с именем, завершаемой нулевым символом. Имя может быть длиной до MAX_PATH знаков (это значение определено как 260).
Разумеется, любой процесс может получить свой ("процессозависимый") описатель существующего объекта "ожидаемый таймер", вызвав OpenWaitableTimer().
HANDLE OpenWaitableTimer( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpszName);
Функция DuplicateHandle() создает копию указанного дескриптора объекта, описана в файле winbase.h и имеет следующий синтаксис.
BOOL DuplicateHandle (HANDLE hSourceProcess, HANDLE hSourceObject, HANDLE hTargetProcess, LPHANDLE lphTarget, DWORD dwAccessFlags, BOOL , DWORD dwOptions);
Параметры:
hSourceProcess - процесс, которому принадлежит дублируемый дескриптор. Объект исходного процесса должен быть открыт.
hSourceObject - Дескриптор дублируемого объекта. Это дескриптор открытого объекта, действительный в контексте исходного процесса. Перечень объектов, дескрипторы которых могут быть дублированы приведены в табл.1.
hTargetProcess - Открытый процесс, для которого создается копия дескриптора.
lphTarget - указатель на переменную, которая принимает дублированный дескриптор. Если значение параметра равно NULL, тогда рассматриваемая функция дублирует дескриптор, но не возвращает значение дублированного дескриптора в место вызова.
dwAccessFlags - набор флагов доступа для нового дескриптора объекта.
bInherit - определяет будет или нет объект наследоваться процессами, порожденными целевым процессом.
dwOptions - дополнительные опции.
Возвращаемое значение: В случае успешного завершения функция возвращает значение TRUE, иначе - FALSE, что означает появление ошибки.
Таблица 1 Типы объектов, дублируемые функцией DuplicateHandle()
Объект |
Описание |
|
Коммуникационный порт |
Возвращается функцией CreateFile() |
|
Ввод с консоли |
Возвращается функцией CreateFile(), если указан дескриптор CONIN$. |
|
Вывод с консоли |
Возвращается функцией CreateFile(), если указан дескриптор CONOUT$. |
|
Событие |
Возвращается функцией CreateEvent() или функцией OpenEvent() |
|
Файл |
Возвращается функцией CreateFile() |
|
Отображение файла |
Возвращается функцией CreateFileMapping() |
|
Мьютекс |
Возвращается функцией CreateMutex() или функцией OpenMutex() |
|
Именованный канал |
Возвращается функцией CreateNamedPipe() или функцией CreateFile(). Функция CreatePipe() возвращает дескриптор анонимного канала. |
|
Процесс |
Возвращается функцией CreateProcess(), GetCurrentProcess() или функцией OpenProcess() |
|
Ключ системного реестра |
Возвращается функцией RegCreateKeyEx() или функцией RegOpenKeyEx(). |
|
Семафор |
Возвращается функцией CreateSemaphore() или функцией OpenSemaphore() |
|
Поток |
Возвращается функцией CreateProcess(), GetCurrentThread() или функцией CreateThread() |
Объекты "ожидаемый таймер" всегда создаются в занятом состоянии. Чтобы сообщить таймеру, в какой момент он должен перейти в свободное состояние, нужно задать функцию SetWaitableTimer.
BOOL SetWaitableTimer( HANDLE hTimer, const LARGE_INTEGER *pDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, PVOID pvArgToCompletionRoutine, BOOI fResume);
Эта функция принимает несколько параметров, в которых легко запутаться. Очевидно, что hTimer определяет нужный таймер. Следующие два параметра (pDиеТiте и lPeriod) используются совместно, первый из них задает, когда таймер должен сработать в первый раз, второй определяет, насколько часто это должно происходить в дальнейшем. Попробуем для примера установить таймер так, чтобы в первый раз он сработал 1 января 2010 года в 13:00, а потом срабатывал каждые 6 часов.
// объявляем свои локальные переменные
HANDLE hTimer;
SYSTEMTIME st;
FILETIME ftLocal, ftUTC;
LARGE_INTEGER liUTC;
// создаем таймер с автосбросом
hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
// таймер должен сработать в первый раз 1 января 2010 года в 13:00
// но местному времени
st.wYear = 2010; // год
st.wMonth = 1; // январь
st.wDayOfWeek = 0; // игнорируется 0
st.wDay = 1, // первое число месяца
st.wHour = 13; // 1 PM
st.wMinute = 0; // 0 минут
st.wSecond = 0, / 0 секунд
st.wMilliseconds = 0; // 0 миллисекунд
SystemTimeToFileTime(&st, &ftLocal);
// преобразуем местное время в UTC-время
LocalFileTimeToFileTime(&ttLocal, &ftUTC);
// преобразуем FILETIME в LARGE_INTEGER из-за различий в выравнивании данных
liUTC.LowPart = ftUTC.wLowDateTime;
liUTC.HighPart = ftUTC dwHighDateTime;
// устанавливаем таймер
SetWaitablcTimer(hTimer, &liUTC, 6 * 60 * 60 * 1000, NULL, NULL, FALSE); ….
Этот фрагмент кода сначала инициализирует структуру SYSTEMTIME, определяя время первого срабатывания таймера (его перехода в свободное состояние). Это время установлено как местное.
Второй параметр представляется как const LARGE_IN TEGER * и поэтому не позволяет напрямую использовать структуру SYSTEMTIME. Однако двоичные форматы структур FILETIME и LARGE_INTEGER идентичны: обе содержат по два 32-битных значения.
Таким образом, возможно преобразовать структуру SYSTEMTIME в FILETIME. Другая проблема заключается в том, что функция SetWaitable Timer ждет передачи времени в формате UTC (Coordinated Universal Time). Нужное преобразование легко осуществляется вызовом LocalFileTimeToFileTime ().
Поскольку двоичные форматы структур FILETIMF, и IARGE_INTEGER идентичны, может появиться искушение передать в SetWaitableTimer адрес структуры FILETIME напрямую;
// устанавливаем таймер SetWaitableTimer(hTimer, (PLARGE_INTEGER) &ftUTC, 6 * 60 * 60 * 1000, NULL, NULL, FALSE);
Но это большая ошибка! Хотя двоичные форматы структур FILETIME и LARGE_INTEGER совпадают, выравнивание этих структур осуществляется по-разному. Адрес любой структуры FILETIME должен начинаться на 32-битной границе, а адрес любой структуры LARGE_INTEGER -- на 64-битной. Вызов SetWaitableTimer с передачей ей структуры FILETIME может сработать корректно, но может и не сработать -- все зависит от того, попадет ли начало структуры FlLETIME на 64-битную границу. В то же время компилятор гарантирует, что структура LARGE_INTEGER всегда будет начинаться на 64-битной границе, и по этому правильнее скопировать элементы FILETIME в элементы LARGE_INTEGER, а за тем передать в SetWaitableTtmer адрес именно структуры LARGE_INTEGER.
NOTE: Процессоры x86 всегда "молча" обрабатывают ссылки на невыровненные данные. Поэтому передача в SetWaitableTimer адреса структуры FILETIME будет срабатывать, если приложение выполняется на машине с процессором x86. Однако другие процессоры (например, Alpha) в таких случаях, как правило, не генерируют исключение EXCEPTION_DATATYPE_MISALIGNMENT, которое приводит к завершению процесса Ошибки.
Чтобы разобраться в том, как заставить таймер срабатывать каждые 6 часов (начиная с 1:00 PM 1 января 2010 года), рассмотрим параметр lPeriod функции SetWaitable Timer. Этот параметр определяет последующую частоту срабатывания таймера (в мс). Чтобы установить 6 часов, передаем значение, равное 21 600 000 мс (т e. 6 часов * 60 минут * 60 секунд * 1000 миллисекунд).
Следующий код демонстрирует, как установить таймер на первое срабатывание через 5 секунд после вызова SetWaitableTimer.
//объявляем свои локальные переменные
HANDLF hTimer;
LARGE_INTEGER li;
// создаем таймер с автосбросом
hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
// таймер должен сработать через 5 секунд после вызова SetWaitableTimer;
// задаем время в интервалах по 100 нс
const int nTimerUnitsPerSecond = 10000000;
// делаем полученное значение отрицательным, чтобы SetWaitableTimer знал:
// нам нужно относительное, а не абсолютное время li.
QuadPart = -(5 * nTimerUnitsPerSecond);
// устанавливаем таймер (он срабатывает сначала через 5 секунд,
// а потом через каждые 6 часов)
SetWaitableTimer(hTimer, &li, 6 * 60 * 60 * 1000, NULL, NULL, FALSE);
...
Обычно нужно, чтобы таймер сработал только раз -- через определенное (абсолютное или относительное) время перешел в свободное состояние и уже больше никогда не срабатывал. Для этого достаточно передать 0 в параметре lPeriod Затем можно либо вызвать CloseHandle, чтобы закрыть таймер, либо перенастроить таймер повторным вызовом SetWattableTimer с другими параметрами
И о последнем параметре функции SetWaitableTimer -- lResume. Он полезен на компьютерах с поддержкой режима сна. Обычно в нем передают FALSE, и в приведенных ранее фрагментах кода это продемонстрировано.
Но если пишется программа - планировщик, которая позволяет устанавливать таймеры для напоминания о запланированных встречах, то нужно передавать в этом параметре TRUE.
Когда таймер сработает, машина выйдет из режима сна (если она находилась в нем), и пробудятся потоки, ожидавшие этот таймер. Далее программа сможет проиграть какой-нибудь WAV-файл и вывести окно с напоминанием о предстоящей встрече. Если же передать FALSE в параметре fResume, объект- таймер перейдет в свободное состояние, но ожидавшие его потоки не получат процессорное время, пока компьютер не выйдет из режима сна
Рассмотрение ожидаемых таймеров было бы неполным, пропусти функцию CancelWaitable Timer.
BOOL CancelWaitableTimer(HANDLE hTimer);
Эта очень простая функция принимает описатель таймера и отменяет его (таймер), после чего тот уже никогда не сработает, -- если только не переустановить его повторным вызовом SetWaitableTimer(). Кстати, если понадобится перенастроить таймер, то вызывать CancelWattableTimer перед повторным обращением к SetWaitableTimer не требуется; каждый вызов SetWaitableTimer автоматически отменяет предыдущие настройки перед установкой новых.
Подобные документы
Разработка приложения, автоматизирующего процесс синхронизации файлов между сменным носителем и каталогом на другом диске. Классы для работы с файловой системой. Интерфейс программы и способы взаимодействия пользователя с ним. Создание новой синхропары.
курсовая работа [632,0 K], добавлен 21.10.2015Функции программного интерфейса операционной системы Windows, предназначенные для работы с семафорами. Средства синхронизации Win32 АРI, основанные на использовании объектов исполнительной системы с дескрипторами. Проблемы при использовании семафоров.
реферат [67,4 K], добавлен 06.10.2010Понятие процесса и потока, характеристика их свойств и особенности создания. Требования к алгоритмам синхронизации, суть взаимного исключения на примере монитора и семафора. Методика изучения элективного курса "Процессы в операционной системе Windows".
дипломная работа [1,7 M], добавлен 03.06.2012Классификация компьютерной памяти. Использование оперативной, статической и динамической оперативной памяти. Принцип работы DDR SDRAM. Форматирование магнитных дисков. Основная проблема синхронизации. Теория вычислительных процессов. Адресация памяти.
курсовая работа [1,5 M], добавлен 28.05.2016Основные ограничения синхронизации, необходимые для корректного функционирования системы. Добавление в код производителя и потребителя операторов синхронизации для обеспечения ее корректной работы. Сигнал конечного буфера производителя-потребителя.
курсовая работа [167,0 K], добавлен 05.12.2012Исследование принципа действия поэлементной синхронизации с добавлением и вычитанием импульсов. Характеристика кодирования в системах ПДС, классификации кодов, построения кодера и декодера циклического кода. Расчет параметров системы с ОС и ожиданием.
курсовая работа [2,8 M], добавлен 08.12.2011Общая характеристика потока как последовательности инструкций, которые считывает и исполняет процессор. Анализ преимуществ одно- и многопроцессорности. Особенности реализации потоков и технологий взаимосвязей с микроархитектурой. Средства синхронизации.
курсовая работа [27,4 K], добавлен 18.05.2013Основные понятия о процессах. Взаимное исключение критических интервалов. Общий подход к построению механизмов синхронизации с использованием концепции критических участков. Основные преимущества алгоритма Декера. Графическое решение задачи о стрелках.
курсовая работа [1,3 M], добавлен 16.12.2014Особенности разработки при использовании потоков. Создание, удаление переменных. Свойства, управление потоками. Вызовы для создания мутекс. Причины завершения потока. Методы синхронизации выполнения потоков. Типичная последовательность действий с мутест.
лекция [160,8 K], добавлен 29.07.2012Взаимодействие процессов и потоков в операционной системе, основные алгоритмы и механизмы синхронизации. Разработка школьного курса по изучению процессов в операционной системе Windows для 10-11 классов. Методические рекомендации по курсу для учителей.
дипломная работа [3,2 M], добавлен 29.06.2012