Системне програмне забезпечення / Лабораторні / Semestr2 / Lab5
.docЛабораторна робота N 5
Тема: Синхронизація потоків
Завдання: Скласти програму і запустити процес в якому ініціалізується і заповнюється дійсними числами двомірний масив 3*10 елементів створюються 4-ри потоки в яких виконується:
-
в 1-му складаються всі елементи 1-го рядка
-
в 2-му від суми парних елементів віднімається сума непарних 2-го рядка
-
в 3-му сума додатніх елементів ділиться на суму від’ємних 3-го рядка
-
всі результати обчислень передаються в 4-й потік, який в цей час чекає на результати роботи 1...3 потоків за допомогою конструкції:
while (!proceed)
Thread.Sleep(x);
Отримавши результати 4-й потік одразу виводить їх на екран і сумує потім виводить суму всіх 4-х результатів і процес завершується.
Теоритичні відомості:
Важнейшие средства синхронизации
В следующих таблицах приведена информация об инструментах .NET для координации (синхронизации) потоков:
Конструкция |
Назначение |
Sleep |
Блокировка на указанное время |
Join |
Ожидание окончания другого потока |
Простейшие методы блокировки
Конструкция |
Назначение |
Доступна из других процессов? |
Скорость |
lock |
Гарантирует, что только один поток может получить доступ к ресурсу или секции кода. |
нет |
быстро |
Mutex |
Гарантирует, что только один поток может получить доступ к ресурсу или секции кода. Может использоваться для предотвращения запуска нескольких экземпляров приложения. |
да |
средне |
Semaphore |
Гарантирует, что не более заданного числа потоков может получить доступ к ресурсу или секции кода. |
да |
средне |
Блокировочные конструкции
(Для автоматической блокировки также могут использоваться контексты синхронизации.)
Конструкция |
Назначение |
Доступна из других процессов? |
Скорость |
EventWaitHandle |
Позволяет потоку ожидать сигнала от другого потока. |
да |
средне |
Wait and Pulse* |
Позволяет потоку ожидать, пока не выполнится заданное условие блокировки. |
нет |
средне |
Сигнальные конструкции
Конструкция |
Назначение |
Доступна из других процессов? |
Скорость |
Interlocked* |
Выполнение простых не блокирующих атомарных операций. |
Да – через разделяемую память |
очень быстро |
volatile* |
Для безопасного не блокирующего доступа к полям. |
Да – через разделяемую память |
очень быстро |
Не блокирующие конструкции синхронизации
Блокирование против ожидания в цикле
Поток может ожидать выполнения некоторого условия, непосредственно прокручивая цикл проверки, например:
while (!proceed) ; |
или:
while (DateTime.Now < nextStartTime) ; |
Однако это очень расточительная трата процессорного времени: поскольку CLR и операционная система убеждены, что поток выполняет важные вычисления, ему выделяются соответствующие ресурсы. Поток, который крутится в таком состоянии, не считается заблокированным, в отличие от потока, ожидающего на EventWaitHandle (конструкции, обычно используемой для таких задач).
Иногда используется гибрид блокирования и ожидания в цикле:
while (!proceed) Thread.Sleep(x); // "Spin-Sleeping!" |
Чем больше x, тем эффективнее используется CPU. Платой за компромисс становится увеличение латентности. При превышении 20 мс накладные расходы незначительны – если условие в while не особенно сложное.
За исключением незначительной задержки эта комбинация блокирования и периодических опросов может работать весьма неплохо (вопросы параллельного доступа к флагу proceed рассматриваются в 4-й части). Возможно, самое частое её использование – когда программист уже потерял надежду запустить в работу более продвинутые сигнальные конструкции!