Скачать презентацию Параллельное программирование ПРИМИТИВЫ СИНХРОНИЗАЦИИ ЗАХОД 2 План Скачать презентацию Параллельное программирование ПРИМИТИВЫ СИНХРОНИЗАЦИИ ЗАХОД 2 План

параллельное_программирование_лекция3.pptx

  • Количество слайдов: 64

Параллельное программирование ПРИМИТИВЫ СИНХРОНИЗАЦИИ. ЗАХОД 2. Параллельное программирование ПРИМИТИВЫ СИНХРОНИЗАЦИИ. ЗАХОД 2.

План лекции ◦ Функции синхронизации ◦ Потоки Exit. Thread, Terminate. Thread, проблемы ◦ Suspend. План лекции ◦ Функции синхронизации ◦ Потоки Exit. Thread, Terminate. Thread, проблемы ◦ Suspend. Thread, Resume. Thread ◦ Критическая секция ◦ Dead. Locks, try. . catch … ◦ Spin. Count ◦ ◦ Мьютекс Event Семафор Сравнение примитивов синхронизации

Threads Threads

Threads Threads

Threads Для создания потока нужно: 1. Определить функцию, которая будет работать в отдельном потоке Threads Для создания потока нужно: 1. Определить функцию, которая будет работать в отдельном потоке 2. Определить размер стека, который будет выделен потоку 3. Определить указатель на структуру данных, которая передается в потоковую функцию 4. Вызвать функцию Create. Thread, которая вернет идентификатор и дескриптор потока.

Threads HANDLE Create. Thread ( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, Threads HANDLE Create. Thread ( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, LPVOID lpv. Thread. Parm, DWORD dw. Create, LPDWORD lp. IDThread )

Threads Параметры ◦ lpsa ◦ Атрибуты безопасности (или NULL) ◦ cb. Stack ◦ Размер Threads Параметры ◦ lpsa ◦ Атрибуты безопасности (или NULL) ◦ cb. Stack ◦ Размер стека ◦ Или 0 по умолчанию (1 MB) ◦ lp. Start. Addr ◦ Адрес функции выполнения ◦ lp. Thread. Parm ◦ Ссылка на параметры, которые передаются в функцию

Thread function Class Thread. Base { ◦ DWORD Run(){} } Thread. Base instance = Thread function Class Thread. Base { ◦ DWORD Run(){} } Thread. Base instance = new Thread. Base(); Create. Thread(…Thread. Base. Jump, c, …) DWORD Thread. Base. Jump(LPVOID param) { ((Thread. Base*)c)->Run()}

Thread function DWORD WINAPI My. Thread. Func ( PVOID p. Th. Param ) { Thread function DWORD WINAPI My. Thread. Func ( PVOID p. Th. Param ) { while(Is. Running) { // is running } Exit. Thread (Exit. Code); return Exit. Code; } /* OR */

Threads Параметры ◦ dw. Create ◦ Если 0, то поток сразу запускается ◦ если Threads Параметры ◦ dw. Create ◦ Если 0, то поток сразу запускается ◦ если CREATE_SUSPENDED, поток создается остановленным. Для запуска требуется вызов Resume. Thread ◦ lp. IDThread ◦ Адрес переменной для получения уникального идентификатора потока

Thread Termination При завершении потока: ◦ ◦ Ресурсы потока освобождаются Устанавливается код выхода из Thread Termination При завершении потока: ◦ ◦ Ресурсы потока освобождаются Устанавливается код выхода из потока Объект потока устанавливается в значение Signaled (Активно) При закрытии последнего потока завершается процесс Как завершить поток: ◦ ◦ ◦ Завершается функция потока Поток вызывает Exit. Thread Вызывается Exit. Process Вызывается Terminate. Thread Вызывается Terminate. Process

Thread Termination После завершения потока его дескриптор остается в системе. Любой другой поток может Thread Termination После завершения потока его дескриптор остается в системе. Любой другой поток может получить код выхода по дескриптору. BOOL Get. Exit. Code. Thread ( HANDLE h. Thread, LPDWORD lpdw. Exit. Code ) lpdw. Exit. Code ◦ Указатель, куда запишется код потока ◦ Может принимать значение STILL_ACTIVE

Thread function DWORD WINAPI My. Thread. Func ( PVOID p. Th. Param ) { Thread function DWORD WINAPI My. Thread. Func ( PVOID p. Th. Param ) { while(Is. Running) Some. Func() return Exit. Code; } void Some. Func() { //? ? Exit. Thread (Exit. Code); }

Ожидание окончания потока Поток может ожидать окончание другого потока при помощи фунции Wait. For. Ожидание окончания потока Поток может ожидать окончание другого потока при помощи фунции Wait. For. Single. Object или Wait. For. Multiple. Objects ◦ Используются дескипторы потоков Функции ожидают перехода потоков в состояние Signaled ◦ Дескриптор потока становится Signaled когда поток завершается Exit. Thread и Terminate. Thread устанавливают поток в состояние Signaled ◦ Освобождают все объекты, которые ожидают окончания потока Exit. Process устанавливает состояние процесса и всех его потоков в Signaled

Функции ожидания DWORD Wait. For. Single. Object ( HANDLE h. Object, DWORD dw. Time. Функции ожидания DWORD Wait. For. Single. Object ( HANDLE h. Object, DWORD dw. Time. Out ) DWORD Wait. For. Multiple. Objects ( DWORD c. Objects, LPHANDLE lph. Objects, BOOL f. Wait. All, DWORD dw. Time. Out ) Return: причина окончания ожидания

Параметры ожидания Один дескриптор h. Object или массив дескрипторов размером c. Objects, количество c. Параметры ожидания Один дескриптор h. Object или массив дескрипторов размером c. Objects, количество c. Objects не должно превышать MAXIMUM_WAIT_OBJECTS – 64 dw. Time. Out время ожидания в милисекундах ◦ 0 означает, что функция завершается сразу же после проверки состояния указанных объектов ◦ Можно использовать INFINITE для бесконечного ожидания f. Wait. All ◦ Если TRUE, то ожидает все объекты Get. Exit. Code. Thread(…) ◦ Возвращает код завершения потока

Возвращаемые значения функций ожидания Возможные возвращаемые значения ◦ WAIT_OBJECT_0 ◦ Поток завершен ◦ WAIT_OBJECT_0 Возвращаемые значения функций ожидания Возможные возвращаемые значения ◦ WAIT_OBJECT_0 ◦ Поток завершен ◦ WAIT_OBJECT_0 + n, где 0 <= n < c. Objects ◦ Можно вычесть WAIT_OBJECT_0 из возвращаемого значения для определения какой из потоков завершился, Wait. For. Multiple. Objects с f. Wait. All = true ◦ WAIT_TIMEOUT ◦ Вышел таймаут ◦ WAIT_ABANDONED ◦ Для потоков не поддерживается (см. мьютексы) ◦ WAIT_FAILED ◦ Используйте Get. Last. Error для получения кода ошибки

Threads Best Practices ◦ Следить за размером стека при создании потока ◦ Не использовать Threads Best Practices ◦ Следить за размером стека при создании потока ◦ Не использовать Suspend, Resume для синхронизации ◦ Не использовать Terminate. Thread ◦ Использовать try/catch для освобождения ресурсов потока

Threads Synchronization Objects Threads Synchronization Objects

Проблема синхронизации Thread 1 Running Thread 2 M N Ready 4 M = N; Проблема синхронизации Thread 1 Running Thread 2 M N Ready 4 M = N; M = M + 1; 4 5 Running Ready 4 5 5 Running N = M; · · · M = N; M = M + 1; N = M; Ready 5 · · ·

Threads Synchronization Objects Рассмотренные механизмы синхронизации: ◦ Один поток может ожидать завершения другого путем Threads Synchronization Objects Рассмотренные механизмы синхронизации: ◦ Один поток может ожидать завершения другого путем ожидания активного состояния дескриптора потока используя Wait. For. Single. Object or Wait. For. Multiple. Objects ◦ Аналогично и процессы Другие методы: ◦ Чтение из Pipe или Socket которые обеспечивают последовательный доступ к чтению для нескольких потоков ◦ Использование блокировок на уровне файлов или баз данных

Suspend and Resume Threads Каждый поток имеет счетчик ожидания (Suspend count) ◦ Поток рабоатет Suspend and Resume Threads Каждый поток имеет счетчик ожидания (Suspend count) ◦ Поток рабоатет только если значение счетчика равно 0 Поток может быть создан в основленном состоянии. Есть две функции, управляющие значением счетчика: DWORD Resume. Thread (HANDLE h. Thread) DWORD Suspend. Thread (HANDLE h. Thread) Обе возвращают предыдущее значение счетчика 0 x. FFFF indicates failure

Suspend and Resume Threads Спроектированы для отладчиков Не предназначены для синхронизации потоков Suspend and Resume Threads Спроектированы для отладчиков Не предназначены для синхронизации потоков

Synchronization Objects Windows предоставляет четыре базовых типа объектов для синхронизации потоков Три объекта ядра Synchronization Objects Windows предоставляет четыре базовых типа объектов для синхронизации потоков Три объекта ядра (имеют дескрипторы) ◦ Events ◦ Semaphores ◦ Mutexes Четвертый объект – уровня приложения ◦ CRITICAL_SECTION

Critical Sections Critical Sections

CRITICAL_SECTION ◦ Чаще всего это самый оптимальный выбор ◦ Покрывает большинство кейсов синхронизации ◦ CRITICAL_SECTION ◦ Чаще всего это самый оптимальный выбор ◦ Покрывает большинство кейсов синхронизации ◦ “Быстрый мьютекс” ◦ Объект уровня приложения ◦ Требуется вход/выход ◦ Только один поток может находиться в критической секции ◦ Существует отдельный тип CRITICAL_SECTION

Управление критической секцией VOID Initialize. Critical. Section ( LPCRITICAL_SECTION lpcs. Critical. Section) VOID Delete. Управление критической секцией VOID Initialize. Critical. Section ( LPCRITICAL_SECTION lpcs. Critical. Section) VOID Delete. Critical. Section ( LPCRITICAL_SECTION lpcs. Critical. Section)

Управление критической секцией VOID Enter. Critical. Section ( LPCRITICAL_SECTION lpcs. Critical. Section) VOID Leave. Управление критической секцией VOID Enter. Critical. Section ( LPCRITICAL_SECTION lpcs. Critical. Section) VOID Leave. Critical. Section ( LPCRITICAL_SECTION lpcs. Critical. Section) BOOL Try. Critical. Section ( LPCRITICAL_SECTION lpcs. Critical. Section)

Use case ◦ Enter. Critical. Section блокирует выполнение потока, если другой поток уже вошел Use case ◦ Enter. Critical. Section блокирует выполнение потока, если другой поток уже вошел в критическую секцию ◦ Используйте Try. Critical. Section для предотвращения блокировки ◦ Поток может войти в CS более одного раза (“recursive”) ◦ Ожидающий поток продолжает выполнение когда владеющий критической секцией поток выполняет Leave. Critical. Section ◦ Каждому вызову Enter должен соответствовать один Leave ◦ Частое использование: ограничить доступ к глобальной переменной ◦ Не нужно забывать писать volatile!

Синхронизация Thread 1 Running Thread 2 M Idle 4 ECS(&CS); M = N; M Синхронизация Thread 1 Running Thread 2 M Idle 4 ECS(&CS); M = N; M = M + 1; N 4 5 Idle Running ECS(&CS); Running Blocked N = M; LCS (&CS); · · · 5 Running 5 6 6 M = N; M = M + 1; N = M; LCS(&CS); · · ·

Дополнение CRITICAL_SECTIONS работает в контексте приложения ◦ Более быстрая – не требуется доступ к Дополнение CRITICAL_SECTIONS работает в контексте приложения ◦ Более быстрая – не требуется доступ к объектам ядра ◦ Ожидание потоков реализовано на ядерном уровне Чаще всего более быстрая чем мьютексы ◦ Но не всегда ◦ Влияние оказывает количество потоков, процессоров Скорость работы можно ускорить ◦ Подобрать “spin count” ◦ Заменить часть операций на Interlocked functions

Spins (1/3) struct lock { int held = 0; } void acquire (lock) { Spins (1/3) struct lock { int held = 0; } void acquire (lock) { while (!test-and-set(&lock->held)) thread_yield(); } void release (lock) { lock->held = 0; }

Spins (2/3) void acquire (lock) { for(int i=0; i<spins_count; i++) { if(! test-and-set(&lock->held)) return; Spins (2/3) void acquire (lock) { for(int i=0; iheld)) return; } while (!test-and-set(&lock->held)) thread_yield(); }

Spins (3/3) VOID Initialize. Critical. Section. And. Spin. Count ( LPCRITICAL_SECTION lpcs. Critical. Section, Spins (3/3) VOID Initialize. Critical. Section. And. Spin. Count ( LPCRITICAL_SECTION lpcs. Critical. Section, DWORD dw. Spin. Count )

Critical Sections Problems Critical Sections Problems

1. Enter no leave (1/4) CRITICAL_SECTION cs; . . . DWORD Thread. Func (. 1. Enter no leave (1/4) CRITICAL_SECTION cs; . . . DWORD Thread. Func (. . . ) { ECS (&cs); function terminated - Terminate. Thread called - unhandled exception LCS (&cs. N); // not called }

1. Enter no leave (2/4) CRITICAL_SECTION cs; . . . DWORD Thread. Func (. 1. Enter no leave (2/4) CRITICAL_SECTION cs; . . . DWORD Thread. Func (. . . ) { ECS (&cs); try { //? ? LCS (&cs. N); } catch(…) { LCS (&cs. N); throw; } }

1. Enter no leave (3/4) CGuard(CRITICAL_SECTION& lpcs) { Enter. Critical. Section(lpcs) } ~CGuard(CRITICAL_SECTION& lpcs) 1. Enter no leave (3/4) CGuard(CRITICAL_SECTION& lpcs) { Enter. Critical. Section(lpcs) } ~CGuard(CRITICAL_SECTION& lpcs) { Leave. Critical. Section(lpcs) } Resource Acquisition Is Initialization (RAII) pattern

1. Enter no leave (4/4) Void Critical. Section. Function(CRITICAL_SECTION& lpcs) { Cguard(lpcs); // thread 1. Enter no leave (4/4) Void Critical. Section. Function(CRITICAL_SECTION& lpcs) { Cguard(lpcs); // thread safe code }

2. Dead. Lock (1/2) CRITICAL_SECTION cs. M, cs. N; DWORD Thread. Func 1 (. 2. Dead. Lock (1/2) CRITICAL_SECTION cs. M, cs. N; DWORD Thread. Func 1 (. . . ) { ECS (&cs. M); // 1 ECS (&cs. N); // 2 LCS (&cs. N); // 3 LCS (&cs. M); // 4 } DWORD Thread. Func 2 (. . . ) { ECS (&cs. N); // 5 ECS (&cs. M); // 6 LCS (&cs. M); // 7 LCS (&cs. N); // 8 } 1 ECS (&cs. M); Wait For (&cs. N); 5 ECS (&cs. N); Wait For (&cs. M); DEADLOCK

2. Dead. Lock (2/2) CRITICAL_SECTION cs. M, cs. N; DWORD Thread. Func 1 (. 2. Dead. Lock (2/2) CRITICAL_SECTION cs. M, cs. N; DWORD Thread. Func 1 (. . . ) { ECS (&cs. M); // 1 ECS (&cs. N); // 2 LCS (&cs. N); // 3 LCS (&cs. M); // 4 } DWORD Thread. Func 2 (. . . ) { ECS (&cs. M); // 5 ECS (&cs. N); // 6 LCS (&cs. N); // 7 LCS (&cs. M); // 8 } 1 ECS (&cs. M); 5 Wait For (&cs. M);

CS Best Practices ◦ Использовать иерархию критических секций ◦ Использовать try/catch для гарантии вызова CS Best Practices ◦ Использовать иерархию критических секций ◦ Использовать try/catch для гарантии вызова Leave. Critical. Section ◦ Использовать библиотеки (std, boost) ◦ Инкапсулировать работу с CS внутри классов

Mutex Mutex

Mutex ◦ Имеют имя и дескриптов ◦ Являются объектами ядра ◦ Могут использоваться для Mutex ◦ Имеют имя и дескриптов ◦ Являются объектами ядра ◦ Могут использоваться для межпроцессной синхронизации ◦ Управляются потоком, а не процессом ◦ Поток захватывает Mutex путем ожидания его дескриптора ◦ Wait. For. Single. Object или Wait. For. Multiple. Objects ◦ Поток освобождает Mutex вызовом Mutex Release. Mutex

Mutex ◦ Рекурсивность: поток может забирать Mutex несколько раз, но должен столько же раз Mutex ◦ Рекурсивность: поток может забирать Mutex несколько раз, но должен столько же раз его освободить ◦ Может быть удобно с вложенными транзакциями ◦ You can poll a mutex to avoid blocking ◦ Mutex переходит в состояние Abandoned если владеющий поток завершается

Mutex HANDLE Create. Mutex (LPSECURITY_ATTRIBUTES lpsa, BOOL f. Initial. Owner, LPCTSTR lpsz. Mutex. Name) Mutex HANDLE Create. Mutex (LPSECURITY_ATTRIBUTES lpsa, BOOL f. Initial. Owner, LPCTSTR lpsz. Mutex. Name) ◦ f. Initial. Owner флаг, если TRUE, вызывающий поток захватывает мьютекс ◦ lpsz. Mutex. Name имя мьютекса ◦ case sensitive ◦ Если NULL, то неименованный

Mutex BOOL Release. Mutex (HANDLE h. Mutex) ◦ Release. Mutex освобождает Mutex ◦ Ошибка Mutex BOOL Release. Mutex (HANDLE h. Mutex) ◦ Release. Mutex освобождает Mutex ◦ Ошибка если поток не владеет мьютексом ◦ Если mutex в состоянии abandoned, функция ожидания вернет WAIT_ABANDONED_0 ◦ Open. Mutex подключается к уже созданому мьютексу ◦ Позволяет обеспечить синхронизацию потоков из разных процессов

Mutex Именование: ◦ Чтобы использовать Mutex в разных процессах его необходимо именовать ◦ Mutexes, Mutex Именование: ◦ Чтобы использовать Mutex в разных процессах его необходимо именовать ◦ Mutexes, semaphores и events используют единое пространство имен ◦ Memory mapping objects also use this name space ◦ So do waitable timers ◦ Для использования в одном процессе мьютекс можно не именовывать

Mutex Межпроцессное взаимодействие Process 1 h = Create. Mutex (

Events Events

Events (1/6) ◦ Событие могут запустить одновременно несколько ожидающих потоков одновременно ◦ manual-reset event Events (1/6) ◦ Событие могут запустить одновременно несколько ожидающих потоков одновременно ◦ manual-reset event – посылают сигнал всем ожидающим потокам, должны сбрасываться одним из потоков ◦ An auto-reset event - посылают сигнал одному потоку и сбрасываются автоматически ◦ Активируется вызовом Pulse. Event или Set. Event ◦ Получается четыру комбинации с различным поведением ◦ Рекомендуется использовать Signal. Object. And. Wait(0)

Events (2/6) HANDLE Create. Event ( LPSECURITY_ATTRIBUTES lpsa, BOOL f. Manual. Reset, BOOL f. Events (2/6) HANDLE Create. Event ( LPSECURITY_ATTRIBUTES lpsa, BOOL f. Manual. Reset, BOOL f. Initial. State, LPTCSTR lpsz. Event. Name) ◦ Manual-reset event: f. Manual. Reset = TRUE ◦ Активное состояние, если f. Initial. State = TRUE ◦ Можно открыть существующий Event через Open. Event ◦ Из другого процесса

Events (3/6) Событиями управляют три функции: BOOL Set. Event (HANDLE h. Event) BOOL Reset. Events (3/6) Событиями управляют три функции: BOOL Set. Event (HANDLE h. Event) BOOL Reset. Event (HANDLE h. Event) BOOL Pulse. Event (HANDLE h. Event)

Events (4/6) ◦ Поток активирует событие вызовом Set. Event ◦ Если событие auto-reset, то Events (4/6) ◦ Поток активирует событие вызовом Set. Event ◦ Если событие auto-reset, то освобождается только один из потоков (возможно многих ожидающих) ◦ Событие автоматически сбрасывается ◦ Если нет ни одного ожидающего потока, то событие будет активно до появления первого, после чего автоматически сбросится

Events (5/6) ◦ Если событие manual-reset, событие остается активным до вызова Reset. Event ◦ Events (5/6) ◦ Если событие manual-reset, событие остается активным до вызова Reset. Event ◦ За это время все ожидающие потоки буду запущены ◦ Pulse. Event позволяет запустить все потоки, ожиающие в данный момент это событие ◦ Событие автоматически сбрасывается

Events (6/6) ◦ При использовании Wait. For. Multiple. Events, выполяется ожидание всех событий из Events (6/6) ◦ При использовании Wait. For. Multiple. Events, выполяется ожидание всех событий из списка ◦ Поток будет запущен если все события одновременно будут активны ◦ Некоторые из событий могут быть сброшены до освобождения потока

Events ◦ Поведение в зависимости от ручного или авто режима, Pulse или Set. Event Events ◦ Поведение в зависимости от ручного или авто режима, Pulse или Set. Event вызова Auto. Reset Manual. Reset Set. Event Exactly one thread is released. If none are currently waiting on the event, the next thread to wait will be released. All currently waiting threads released. The event remains signaled until reset by some thread. Pulse. Event Exactly one thread is released, but only if a thread is currently waiting on the event. All currently waiting threads released, and the event is then reset.

Semaphores Semaphores

Semaphore ◦ https: //habrahabr. ru/post/261273 Semaphore ◦ https: //habrahabr. ru/post/261273

Сравнение Сравнение

Critical section Critical section

Mutex Mutex

Semaphore Semaphore

Events Events