КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Лекция №8. Особенности: volatile BOOL g_fFinished = FALSE;
Особенности:
/*volatile – загружаем значение из памяти при каждом обращении к переменной (отключает оптимизации компилятора).*/
int main() { CreateThread (…, CalcFunc,…); While (g_fFinished = = FALSE); } DWORD WINAPI CalcFunc (PVOID) { … g_fFinished = TRUE; }
Если не будем использовать ключевое слово volatile, то возникнет риск того, что значения флага загрузятся в регистр процессора перед вычислением while, и в дальнейшем проверяться будет значение из регистра, т.е. ждущий процесс никогда не увидит окончания вычислений.
При реализации спин-блокировки возможна ситуация, когда поток длительное время опрашивает условие входа E, периодически это условие оказывается истинным, тем не менее, поток не может войти в критический участок. Происходит «отталкивание» (starvation, голодание). Можно решить, добавив Sleep(0) в конец Thr1.
volatile int x = 0; // Thread1() x++ volatile int y = 0; // Thread2() y++ Для ускорения работы с ОЗУ каждый из процессоров использует локальный КЭШ, однако подгрузка в КЭШ производится не побайтно, а загружается целиком КЭШ-линия (участок памяти, выровненный по 32-байтной границе). Если две переменные попадают в одну КЭШ-линию, то эффект от использования КЭШа пропадает: нужно обновлять данные и в ОЗУ и во втором КЭШе. Поэтому следует выровнять переменные по границам КЭШ-линии или вводить фиктивные переменные, чтобы гарантировать, что переменные не попадут в одну КЭШ-линию. Для того чтобы избежать этих проблем, в Windows реализован такой объект, как критическая секция.
Критическая Секция Windows void InitializeCriticalSection (PCritical_Section); void DeleteCriticalSection(); void EnterCriticalSection(); bool TryEnterCriticalSection(); void LeaveCriticalSection(); bool InitializeCriticalSectionAndCount(); setCriticalSectionSpinCount();
Достоинство: высокое быстродействие. Недостатки: interlocked функции не переводят поток в режиме ожидания, нельзя указать тайм-аут, нельзя использовать при межпроцессном взаимодействии.
Синхронизация в режиме ядра Для такой синхронизации используются объекты ядра, которые могут находиться в сигнальном (свободном) и несигнальном (занятом) состоянии. Это – процессы, потоки, задания, файлы, консольный ввод, уведомления об изменении файлов, события, ожидаемые таймеры, мьютексы, семафоры. WaitForSingleObject(HANDLE, DWORD dwMultiSec); WaitForMultipleObject(…, BOOL fWaitAll, …); Если происходит переход объект в сигнальное состояние в момент блокировки, то обычно происходит снятие блокировки, и выполняются некоторые действия, зависящие от объекта ядра. Возвращают: - В случае завершения тайм-аута: WAIT_TIMEOUT; - В случае ошибки: WAIT_FAILED; - “Указатель” на следующий в порядке ожидания объект: WAIT_OBJECT_0; Чтобы узнать, какой именно объект перешел в сигнальное состояние, проверяем, что значение не равно WAIT_FAILED и WAIT_TIMEOUT и вычитаем из него WAIT_OBJECT_0 и получаем индекс в массиве, переданном в WaitForMultipleObject().
Управление объектами ядра Создание CreateMutex() Закрытие BOOL CloseHandle(HANDLE) Каждый процесс имеет таблицу описателей: При закрытии HANDLE мы удаляем описатель из таблицы и декрементируем счетчик i. Если i = 0 – уничтожение объекта. Наследование: SECURITY_ATTRIBUTE sa; sa.nlength = sizeof(sa); sa.lpSecurityDescriptor=NULL; /*NULL – защита по умолчанию; определяет, кто может пользоваться объектом (при NULL – создатель процесса и администраторы) */ sa.bInHeritHandle=TRUE; /*наследовать HANDLE*/ HANDLE hMutex = CreateMutex (&sa, FALSE, NULL);
Для передачи описателя в дочерний процесс обычно используется командная строка или переменные окружения. Если объект создается уже после создания дочернего процесса, то дочерний процесс не содержит наследованного описателя.
Дата добавления: 2014-12-07; Просмотров: 387; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |