
Системне програмне забезпечення / Лабораторні / Semestr2 / Lab7
.docЛабораторна робота N 7
Тема:
Синхронизація потоків. Використання семафорів.
Теоретичні відомості:
Semaphore
Semaphore похож на ночной клуб – он имеет определенную вместимость, которую обеспечивает вышибала. После заполнения никто уже не может войти в ночной клуб, очередь образуется снаружи. Далее, если один человек покидает клуб, один из начала очереди может пройти внутрь. Конструктор Semaphore принимает минимум два параметра – число еще доступных мест и общую вместимость ночного клуба.
Semaphore с емкостью, равной единице, подобен Mutex или lock, за исключением того, что он не имеет потока-хозяина. Любой поток может вызвать Release для Semaphore, в то время как в случае с Mutex или lock только поток, захвативший ресурс, может его освободить.
В следующем примере по очереди запускаются десять потоков, выполняющих вызов Sleep. Semaphore гарантирует, что не более трех потоков могут вызвать Sleep одновременно:
class SemaphoreTest { static Semaphore s = new Semaphore(3, 3); // Available=3; Capacity=3
static void Main() { for (int i = 0; i < 10; i++) new Thread(Go).Start(); }
static void Go() { while (true) { s.WaitOne(); // Только 3 потока могут находиться здесь одновременно Thread.Sleep(100); s.Release(); } } } |
WaitAny, WaitAll и SignalAndWait
Кроме Set и WaitOne, есть еще несколько статических методов класса WaitHandle для более крепких орешков синхронизации.
Методы WaitAny, WaitAll и SignalAndWait облегчают взаимодействие нескольких WaitHandle, возможно разных типов.
SignalAndWait, возможно, самый полезный метод – он в рамках единой атомарной операции вызывает WaitOne для одного WaitHandle, и Set – для другого.
Классическим вариантом использования этого метода является использование с парой EventWaitHandle для подготовки встречи двух потоков в нужной точке в нужное время. Подойдут и AutoResetEvent и ManualResetEvent. Первый поток делает следующее:
WaitHandle.SignalAndWait(wh1, wh2); |
в то время как второй поток – наоборот:
WaitHandle.SignalAndWait(wh2, wh1); |
WaitHandle.WaitAny ожидает освобождения одного (любого) WaitHandle из переданного ему списка, WaitHandle.WaitAll ожидает освобождения сразу всех переданных ему WaitHandle. Используя аналогию с турникетом метро, эти методы организуют общую очередь одновременно для всех турникетов – с прохождением через первый открывшийся турникет (WaitAny) или с ожиданием, пока они не откроются все (WaitAll).
На самом деле, значение WaitAll сомнительно из-за странной связи с потоковыми апартаментами, унаследованными от COM-архитектуры. WaitAll требует, чтобы вызывающий поток находился в многопоточном апартаменте, в то время как эта модель может быть наименее подходящей, особенно для приложений Windows Forms, которые должны выполнять столь мирские задачи, как взаимодействие с буфером обмена.
К счастью, .NET Framework обеспечивает более продвинутый сигнальный механизм для случаев, когда WaitHandle являются неудобными или неподходящими – Monitor.Wait и Monitor.Pulse.
Завдання:
Скласти програму, в якій запустити 2 процеси з 2-ма потоками в кожному, в кожному процесі задати 2 масиви по 100 цілих чисел і заповнити їх довільними числами. Відкрити в одному потоці 2 текстових файли, ініціалізувати семафор, виконати запис елементів масивів в файли за наступним алгоритмом. Потоки 1/1 (№ процесу/№ потоку) та 1/2 захоплюють і блокують семафор заносять по 25 перших елементів своїх масивів в файл 1, а 25 наступних в файл 2, потім розблоковують семафор, потік 2/1 та 2/2 захоплюють семафор і виконують те саме. Повторити операцію поки всі елементи масивів не будуть передані в файл.