Синхронизация потоков в режиме ядра
Синхронизация потоков связана с атомарным доступом — монопольным захватом ресурса, обращающимся к нему потоком. Свойства и принцип действия Interlocked-функций. Общее понятие и инициализация критической секции. Вход в критическую секцию и выход из нее.
Рубрика | Коммуникации, связь, цифровые приборы и радиоэлектроника |
Вид | контрольная работа |
Язык | русский |
Дата добавления | 03.10.2010 |
Размер файла | 22,7 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
СИНХРОНИЗАЦИЯ ПОТОКОВ В РЕЖИМЕ ЯДРА
1 БЛОКИРУЮЩИЕ ПЕРЕМЕННЫЕ
Большая часть синхронизации потоков связана с атомарным доступом (atomic access) -- монопольным захватом ресурса обращающимся к нему потоком. Возьмем простой пример
// определяем глобальную переменную
long x = 0;
DWORD WINAPI ThreadFunc1(PVOID pvParam)
{ x++; return(0);
}
DWORD WINAPI ThreadFunc2(PVOID pvParam}
{ x++; return(0);
}
Пусть объявлена глобальная переменная x с начальным нулевым значением. после этого создано два потока:
один выполняет ThreadFunc1,
другой -- ThreadFunc2
Код этих функций идентичен: обе увеличивают значение глобальной переменной x на 1. Чему будет равно значение глобальной переменной x?
Windows -- это среда, которая поддерживает многопоточность и вытесняющую многозадачность.
Значит, процессорное время в любой момент может быть отнято у одного потока и передано другому.
Тогда получение x равным 2 может достаточно проблематичным. Ведь неизвестно сколько удалось кванта времени планировщику выделить для каждого из потоков.
Решение этой проблемы должно быть простым. Все, что нам нужно, -- это способ, гарантирующий приращение значения переменной на уровне атомарного доступа, т.e. без прерывания другими потоками.
Для этого служит семейство Interlocked-функций. Все функции из этого семейства манипулируют переменными на уровне атомарного доступа. В группу функций входят:
1. InterlockedExchange().
2. InterlockedExchangeAdd().
3. InterlockedIncrement().
4. InterlockedDecrement().
5. InterlockedExchangePointer().
6. InterlockedCompareExchange().
7. InterlockedCompareExchangePointer().
Как же работают Interlocked-функции? Ответ зависит от того, какая процессорная платформа используется. Так, например, на компьютерах с процессорами семейства Intel x86 эти функции выдают по шине аппаратный сигнал, не давая другому процессору обратиться по тому же адресу памяти.
На платформе Alpha Interlocked-функции действуют примерно так:
1. Устанавливают специальный битовый флаг процессора, указывающий, что данный адрес памяти сейчас занят.
2. Считывают значение из памяти в регистр.
3. Изменяют значение в регистре.
4. Если битовый флаг сброшен, повторяют операции, начиная с п. 2. В ином случае значение из регистра помещается обратно в память.
Другой важный аспект, связанный с Interlocked-функциями, состоит в том, что они выполняются чрезвычайно быстро. Вызов такой функции обычно требует не более 50 тактов процессора, и при этом не происходит перехода из пользовательского режима в режим ядра (а он отнимает не менее 1000 тактов).
Рассмотрим Interlocked-функции подробнее.
Функция InterlockedExchange() обменивает 32-разрядное значение синхронизированной переменной на другое длинное (long) значение. Синтаксис функции следующий
LONG InterlockedExchange (LPLONG lpTarget, LONG lNewVal)
Параметры:
lpTarget - указатель на синхронизируемую переменную, значение которой подлежит обмену;
lNewVal - новое значение, которое подлежит сохранению в синхронизированной переменной.
Возвращаемое значение. Возвращается прежнее значение переменной, на которую указывает lpTarget.
При этом гарантируется, что операция не будет прервана другим потоком, выполняющемся в рамках того же процесса, ведь синхронизация этой переменной обеспечивается операционной системой.
Аналогичной функцией выступает функция InterlockedExchangeAdd(), которая выполняет элементарное сложение, увеличивающее значение указанной переменной. Синтаксис функции следующий
LONG InterlockedExchangeAdd (PLONG pAddend, LONG lIncrement )
Параметры:
pAddend - адрес числа, к которому прибавляется число, определенное параметром lIncrement;
lIncrement - число, прибавляемое к значению переменной, на которую указывает параметр pAddend.
Возвращаемое значение. Возвращается прежнее значение переменной, на которую указывает pAddend.
InterlockedExchangeAdd() позволяет не только увеличить, но и уменьшить значение -- просто необходимо во втором параметре передать ей отрицательную величину.
Функции InterlockedIncrement() и InterlockedDecrement() выполняют, соответственно, увеличение и уменьшение на единицу значения переменной типа LONG, адрес которой передается им в качестве единственного параметра:
LONG InterlockedIncrement(LPLONG lpAddend);
LONG InterlockedDecrement(LPLONG lpAddend).
Особенностью этих функций является то, что если один поток приступил с их помощью к изменению значения переменной, то другой поток не сможет выполнить изменение этой же переменной до тех пор, пока первый поток не завершит такое изменение.
В Win64 API-интерфейс добавлена еще одна Interlocked-функция - InterlockedExchangePointer(), основное отличие которой от InterlockedExchang() заключается в оперировании с 64-разрядными данными.
Оставшаяся пара функций InterlockedCompareExchange() и InterlockedCompareExchangePointer() выполняют операцию сравнения и присвоения на уровне атомарного доступа.
В 32-разрядном приложении обе функции работают с 32-разрядными значениями, но в 64-разрядном приложении InterlockedCompareExchange() используется для 32 разрядных значений, a InterlockedCompareExcbangePointer() - для 64-разрядных. Функция сравнивает текущее значение переменной типа LONG (на которую указывает параметр pIDestination) со значением, передаваемым в параметре lComparand. Если значения совпадают, *pIDestination получает значение параметра lExchange; в ином случае *pIDestination остается без изменений. Синтаксис функции следующий
PVOID InterlockedCompareExchange( PLONG pIDestination, LONG lExchange, LONG lComparand);
PVOID InterlockedCompareExchangePointer( PVOID* ppvDestination, PVOID pvExchange, PVOID pvComparand).
Таким образом, указанные Interlocked-функции обеспечивают простой механизм синхронизации доступа к переменной, которая является общей для нескольких потоков. Эти функции гарантируют монопольное изменение значений переменных независимо от того, как именно компилятор генерирует код и сколько процессоров установлено в компьютере. Однако нужно позаботиться о выравнивании адресов переменных, передаваемых этим функциям, иначе они могут потерпеть неудачу.
2 КРИТИЧЕСКИЕ СЕКЦИИ (РАЗДЕЛЫ)
В однозадачной операционной системе обычные программы не нуждаются в "светофорах" для координации их действий. Они выполняются так, как будто они являются хозяевами дороги, по которой они следуют. Не существует ничего, что могло бы вмешаться в то, что они делают.
Даже в многозадачной операционной системе большинство программ выполняются независимо друг от друга. Но некоторые проблемы все же могут возникнуть.
Например, двум программам может понадобиться читать и писать в один файл в одно и то же время. Для таких случаев операционная система поддерживает механизм разделения файлов (shared files) и блокирования отдельных фрагментов файла (record locking).
Однако, в операционной системе, поддерживающей многопоточность, такое решение может внести путаницу и создать потенциальную опасность. Разделение данных между двумя и более потоками является общим случаем.
Например, один поток может обновлять одну или более переменных, а другой может использовать эти переменные. Иногда в этой ситуации может возникнуть проблема, а иногда -- нет.
Однако, предположим, что потоки разделяют несколько переменных или структуру данных.
Часто эти сложные переменные или поля структур данных должны быть согласованными между собой. Операционная система может прерывать поток в середине процесса обновления этих переменных. В этом случае поток, который затем использует эти переменные, будет иметь дело с несогласованными данными.
В результате бы возникла коллизия, и нетрудно представить себе, как такого рода ошибка может привести к краху программы. В этой ситуации нам необходимо средство, которое могло бы синхронизировать и координировать работу потоков.
Таким средством и является критический раздел. Критический раздел -- это блок кода, при выполнении которого поток не может быть прерван.
Чтобы использовать функции для работы с критическими разделами, необходимо определить объект типа критический раздел, который является глобальной переменной типа CRITICAL_SECTION.
Например,
CRITICAL_SECTION cs ;
Обычно структура CRITICAL_SECTION располагается в области глобальных переменных, доступной всем запущенным задачам процесса.
Так как каждый процесс работает в своем собственном адресном пространстве, то нельзя передать адрес критической секции из одного процесса в другой. Именно поэтому критические секции нельзя использовать для синхронизации задач, созданных разными процессами.
Инициализация критической секции
Перед использованием критической секции ее необходимо проинициализировать, вызвав для этого функцию InitializeCriticalSection():
VOID InitializeCriticalSection (LPCRITICAL_SECTION lpCriticalSection).
Функция InitializeCriticalSection() имеет только один параметр (адрес структуры типа CRITICAL_SECTION) и не возвращает никакого значения.
В документации содержится следующее предупреждение: "Объект критический раздел не может быть перемещен или скопирован".
Процесс также не должен модифицировать объект, а должен обращаться с ним, как с "черным ящиком".
Удаление критической секции
Если критическая секция больше не нужна, ее нужно удалить при помощи функции DeleteCriticalSection(), как это показано ниже:
VOID DeleteCriticalSection (LPCRITICAL_SECTION lpCriticalSection)
Это приведет к освобождению всех ресурсов системы, задействованных для поддержки объекта критический раздел.
Вход в критическую секцию и выход из нее
Две основные операции, выполняемые задачами над критическими секциями, это вход в критическую секцию и выход из критической секции.
Первая операция выполняется при помощи функции EnterCriticalSection(), вторая - при помощи функции LeaveCriticalSection(). Эти функции, не возвращающие никакого значения, всегда используются в паре.
VOID EnterCriticalSection (LPCRITICAL_SECTION lpCriticalSection)
В этот момент поток становится владельцем объекта. Два различных потока не могут быть владельцами одного объекта критический раздел одновременно.
Следовательно, если один поток вошел в критический раздел, то следующий поток, вызывая функцию EnterCriticalSection() с тем же самым объектом критический раздел, будет задержан внутри функции.
Возврат из функции произойдет только тогда, когда первый поток покинет критический раздел, вызвав функцию:
VOID LeaveCriticalSection (LPCRITICAL_SECTION lpCriticalSection)
В этот момент второй поток, задержанный в функции EnterCriticalSection(), станет владельцем критического раздела, и его выполнение будет возобновлено.
Например, как это показано в следующем фрагменте исходного текста:
EnterCriticalSection(&cs);
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc);
DrawText(hdc, "SDI Window", -1, &rc,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
LeaveCriticalSection(&cs);
В качестве единственного параметра функциям EnterCriticalSection() и LeaveCriticalSection() необходимо передать адрес структуры типа CRITICAL_SECTION, проинициализированной предварительно функцией InitializeCriticalSection().
Принцип работы.
Если одна задача вошла в критическую секцию, но еще не вышла ее, то при попытке других задач войти в ту же самую критическую секцию они будут переведены в состояние ожидания. Задачи пробудут в этом состоянии до тех пор, пока задача, которая вошла в критическую секцию, не выйдет из нее.
Таким образом гарантируется, что фрагмент кода, заключенный между вызовами функций EnterCriticalSection() и LeaveCriticalSection(), будет выполняться задачами последовательно, если все они работают с одной и той же критической секцией.
Механизм критических секций основан на принципе взаимного исключения (mutual exclusion).
Только один поток может быть владельцем критической секции в каждый конкретный момент времени.
Следовательно, один поток может войти в критическую секцию, установить значения полей структуры и выйти из критической секции.
Другой поток, использующий эту структуру, также мог бы войти в критическую секцию перед осуществлением доступа к полям структуры, а затем выйти из критической секции.
Особенности.
1. Обратите внимание, что возможно определение нескольких объектов типа критический раздел, например, cs1 и cs2.
Если в программе имеется четыре потока, и два первых из них разделяют некоторые данные, то они могут использовать первый объект критический раздел, а два других потока, также разделяющих другие данные, могут использовать второй объект критический раздел.
2. Обратите внимание, что надо быть весьма осторожным при использовании критического раздела в главном потоке.
Если вторичный поток проводит слишком много времени в его собственном критическом разделе, то это может привести к "зависанию" главного потока на слишком большой период времени.
3. В Windows XP потоки, ожидающие освобождения критической секции, никогда не блокируются "навечно" EnterCriticalSection() устроена так, что по истечении определенного времени, генерирует исключение.
После этого можно подключить к своей программе отладчик и посмотреть, что в ней случилось. Длительность времени ожидания функцией EnterCriticaiSection() определяется значением параметра CriticalSectionTimeout, который хранится в следующем разделе системного реестра:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager
Длительность времени ожидания измеряется в секундах и по умолчанию равна 2 592 000 секунд (что составляет ровно 30 суток). Не следует устанавливать слишком малое значение этого параметра (например, менее 3 секунд), так как иначе нарушится работа других потоков и приложений, которые обычно ждут освобождения критической секции дольше трех секунд.
Подобные документы
Тактовая сетевая синхронизация: общие положения, структура сети синхронизации и особенности проектирование схем. Ключевые условия качественной синхронизации цифровых систем. Общие принципы управления в оптической мультисервисной транспортной сети.
реферат [733,8 K], добавлен 03.03.2014Выявление и оценка качества синхросигналов. Принципы построения сети тактовой синхронизации для телекоммуникационной сети. Разработка ситуационной схемы заданного фрагмента тактовой сетевой синхронизации при различных авариях и в нормальном режиме.
курсовая работа [644,2 K], добавлен 03.02.2014Характеристика транспортной сети, общие принципы построения. Характеристики узлового оборудования. Расчет межстанционной нагрузки в рабочем состоянии. Выбор оптических интерфейсов и типов волокон. Тактовая синхронизация сетей, её главные принципы.
курсовая работа [3,5 M], добавлен 14.12.2012Сравнительная характеристика современных телекоммуникационных технологий SDH и PDH. Состав сети SD и типовая структура тракта; функции и структура заголовков. Типы и параметры синхронизации в сетях связи. Разработка тактовой сетевой синхронизации.
дипломная работа [3,5 M], добавлен 17.10.2012Обоснование и выбор системы телеизмерений. Распределители и устройства повышения достоверности. Генератор тактовых импульсов. Синхронизация систем телемеханики с временным разделением сигналов. Демонстрация работы программы на контрольной задаче.
курсовая работа [488,7 K], добавлен 18.01.2014Устройство и принцип действия пролетного усилительного клистрона. Зависимость выходной мощности от мощности, поступающей на вход усилителя. Амплитудно-частотная характеристика двухрезонаторного клистрона. Особенности конструкций пролетных клистронов.
курсовая работа [522,5 K], добавлен 20.08.2015Предпосылки возникновения концепции сетей тактической радиосвязи. Система JTIDS, ее функциональные возможности. Типы сообщений, циркулирующих в системе. Режимы предоставления СВИ. Временная синхронизация сети. Навигационное обеспечение системы.
научная работа [97,2 K], добавлен 26.08.2010Пункты, звенья и режимы сигнализации. Состав сигнальных единиц, их адресация, синхронизация, передача и прием. Прикладная подсистема возможностей транзакций. Алгоритм установления и разъединения соединений в сети с использованием системы сигнализации.
дипломная работа [3,1 M], добавлен 17.08.2016Исследование модели вход-выход. Дифференциальное уравнение описания системы. Начальные условия на интеграторах и выходные сигналы интеграторов. Схемы и графики моделирования. Реакция на нулевое входное воздействие и ненулевые начальные условия.
лабораторная работа [674,6 K], добавлен 27.10.2013Структура фрагмента процессора. Функциональный состав процессорного блока. Входные/выходные сигналы распределителя. Микропрограмма управления для команды. Устройство управления и синхронизации, принцип его работы. Порты ввода, вывода микроконтроллера.
курсовая работа [653,2 K], добавлен 17.04.2015