Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...
Особенности сооружения опор в сложных условиях: Сооружение ВЛ в районах с суровыми климатическими и тяжелыми геологическими условиями...
Топ:
Теоретическая значимость работы: Описание теоретической значимости (ценности) результатов исследования должно присутствовать во введении...
Методика измерений сопротивления растеканию тока анодного заземления: Анодный заземлитель (анод) – проводник, погруженный в электролитическую среду (грунт, раствор электролита) и подключенный к положительному...
Основы обеспечения единства измерений: Обеспечение единства измерений - деятельность метрологических служб, направленная на достижение...
Интересное:
Национальное богатство страны и его составляющие: для оценки элементов национального богатства используются...
Уполаживание и террасирование склонов: Если глубина оврага более 5 м необходимо устройство берм. Варианты использования оврагов для градостроительных целей...
Что нужно делать при лейкемии: Прежде всего, необходимо выяснить, не страдаете ли вы каким-либо душевным недугом...
Дисциплины:
2017-06-11 | 419 |
5.00
из
|
Заказать работу |
|
|
Входящее в состав Win32 API семейство выполняющихся атомарно Interlocked-функций дает ключ к решению многих проблем синхронизации. Например, функция
LONG InterlockedExchangeAdd(PLONG plAddend, LONG lncrement);
позволяет атомарным образом увеличить значение переменной. В этом случае корректное приращение переменной Count, описанное в начале лекции, может быть обеспечено следующей операцией:
InterlockedExchangeAdd (&Count, 1);
В MSDN можно прочитать и про другие Interlocked-функции. Например, в качестве TSL инструкции, необходимой для решения проблемы входа в критическую секцию, можно применить функцию InterlockedCompareExchange.
Реализация Interlocked-функций зависит от аппаратной платформы. На x86-процессорах они выдают по шине аппаратный сигнал, закрывая для других процессоров конкретный адрес памяти.
Существенно то, что Interlocked-функции выполняются в пользовательском режиме работы процессора в течение примерно 50 тактов, то есть чрезвычайно быстро.
Прогон программы синхронизации с помощью переменной замка
Для практического знакомства с проблемой синхронизации вначале необходимо написать программу, требующую синхронизации. Например, такую, как приведенная ниже программа async:
#include <windows.h>
#include <stdio.h>
#include <math.h>
int Sum = 0, iNumber=5, jNumber=300000;
DWORD WINAPI SecondThread(LPVOID){
int i,j;
double a,b=1.;
for (i = 0; i < iNumber; i++)
{
for (j = 0; j < jNumber; j++)
{
Sum = Sum + 1; a=sin(b);
}
}
return 0;
}
void main(){
int i,j;
double a,b=1.;
HANDLE hThread;
DWORD IDThread;
hThread=CreateThread(NULL, 0, SecondThread, NULL, 0, &IDThread);
if (hThread == NULL) return;
for (i = 0; i < iNumber; i++)
{
for (j = 0; j < jNumber; j++)
{
Sum = Sum - 1; a=sin(b);
}
printf(" %d ",Sum);
}
WaitForSingleObject(hThread, INFINITE); // ожидание окончания потока SecondThread
printf(" %d ",Sum);
}
В данной программе поток SecondThread в цикле дает приращение общей переменной Sum, а основной поток также в цикле уменьшает ее значение и периодически выводит его на экран. Вычисление синуса включено в программу для замедления. Легко убедиться, что результаты работы программы вследствие перемешивания непредсказуемы, особенно если параметр jNumber подобрать с учетом быстродействия компьютера.
|
Рекомендуется ввести в данную программу синхронизацию с помощью глобальной переменной-замка, включив в нее операции while(lock); и lock=1; и добиться предсказуемости в работе программы.
Поскольку ситуация, в которой квант времени, выделенный потоку, истекает между while(lock); и lock=1; маловероятна, можно смоделировать ее искусственно, введя между этими операциями паузу (функция Sleep, например). Наконец, желательно реализовать правильное решение путем опроса и модификации переменной замка с помощью TSL-инструкции (функция InterlockedCompareExchange).
Спин-блокировка
Рассмотренные решения проблемы синхронизации, безусловно, являются корректными. Они реализуют следующий алгоритм: перед входом в критическую секцию поток проверяет возможность входа и, если такой возможности нет, продолжает опрос значения переменной-замка. Такое поведение потока, связанное с его вращением в пустом цикле, называется активным ожиданием или спин-блокировкой (spin lock).
Очевидно, что на однопроцессорной машине это пустая трата машинного времени, поскольку значение опрашиваемой переменной в течение этого цикла не может быть волшебным образом изменено.
Спин-блокировка, хотя бы временная, может быть полезна на многопроцессорных машинах, где один из потоков крутится в цикле, а второй - работает на другом процессоре и может изменить значение переменной-замка. В этом случае у активно ожидающего потока есть шанс быстро войти в критическую секцию, не будучи блокированным. Блокировка потока связана с переходом в режим ядра (примерно 1000 тактов работы процессора).
Однако более разумным решением, особенно на однопроцессорных машинах, представляется перевод потока в состояние ожидания, если вход в критическую секцию запрещен. После снятия запрета на вход в критическую секцию этот поток переводится в состояние готовности.
|
Critical 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), которое создается только в случае возникновения конфликтной ситуации.
Уже говорилось, что иногда, перед блокированием потока, имеет смысл некоторое время удерживать его в состоянии активного ожидания. Чтобы функция EnterCriticalSection выполняла заданное число циклов спин-блокировки, критическую секцию целесообразно проинициализировать с помощью функции InitalizeCriticalSectionAndSpinCount.
Прогон программы
В качестве самостоятельного упражнения рекомендуется реализовать синхронизацию в выше приведенной программе async с помощью перечисленных примитивов. Важно не забывать про корректный выход из критической секции, то есть про парное использование функций EnterCriticalSection и LeaveCriticalSection.
|
|
Двойное оплодотворение у цветковых растений: Оплодотворение - это процесс слияния мужской и женской половых клеток с образованием зиготы...
Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰)...
Типы оградительных сооружений в морском порту: По расположению оградительных сооружений в плане различают волноломы, обе оконечности...
Кормораздатчик мобильный электрифицированный: схема и процесс работы устройства...
© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!