Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция 3. Синхронизация потоков.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
203.31 Кб
Скачать

If (!running) { // Остановка часов.

Monitor.Pulse(this); // Уведомление любых

// ожидающих потоков.

return;

}

Console.Write("тик ");

Monitor.Pulse(this); // Разрешает выполнение

// метода tock().

Monitor.Wait(this); // Ожидаем завершения

// метода tock().

}

}

Методы Wait() и Pulse() могут использоваться только в синхронизированных блоках кода. Вначале метода tick() проверяется значение текущего параметра, которое служит явным признаком остановки часов. Если это логическое значение false, то часы остановлены. В этом случае вызывается метод Pulse(), разрешающий выполнение любого потока, ожидающего своей очереди.

Если же часы идут при выполнении метода tick(), то на экран выводится слово "тик" с пробелом, затем вызывается метод Pulse(), а после него - метод Wait(). При вызове метода Pulse() разрешается выполнение потока для того же самого объекта, а при вызове метода Wait() выполнение метода tock() приостанавливается до тех пор, пока метод Pulse() не будет вызван из другого потока. Теперь, уберем методы Wait() иPulse() из созданной ранее программы:

class TickTock

{

public void tick(bool running)

{

lock (this)

{

if (!running)

{ // Остановка часов.

return;

}

Console.Write("тик ");

}

}

public void tock(bool running)

{

lock (this)

{

if (!running)

{ // Остановка часов.

return;

}

Console.WriteLine("так");

}

}

}

При выполнении программа сгенерирует результаты, представленные на Рис. 5.4.

увеличить изображение Рис. 5.4. Результат выполнения программы без использования методов Wait() и Pulse()

Как видно из результатов выполнения программы, методы tick() и tock() больше не синхронизированы.

Класс Mutex

Когда двум или более потокам одновременно требуется доступ к общему ресурсу, системе необходим механизм синхронизации, чтобы обеспечить использование ресурса только одним потоком одновременно. Класс Mutex, определенный в пространстве имен System. Threading - это примитив, который предоставляет эксклюзивный доступ к общему ресурсу только одному потоку синхронизации. Если поток получает семафор, второй поток, желающий получить этот семафор, приостанавливается до тех пор, пока первый поток не освободит семафор. Термин Mutex происходит от фразы mutually exclusive (взаимно исключающий), и поскольку только один поток может получить блокировку монитора для данного объекта в любой момент времени, только один поток в любой момент времени может получить данный Mutex. Класс Mutex очень похож на класс Monitor тем, что тоже допускает наличие только одного владельца. Только один поток может получить блокировку и иметь доступ к защищаемым Mutex синхронизированным областям кода. У Mutex имеется несколько конструкторов. Ниже приведены три наиболее употребительных конструктора:

public Mutex()

public Mutex(bool initiallyOwned);

public Mutex(bool initiallyOwned, string name_mutex)

В первой форме конструктора создается Mutex, которым первоначально никто не владеет. А во второй и третей форме исходным состоянием Mutex завладевает вызывающий поток, если параметр initiallyOwned имеет логическое значение true, если false, то объектом Mutex никто не владеет.

Для того чтобы получить Mutex, используется метод WaitOne(). Метод WaitOne() ожидает до тех пор, пока не будет получен Mutex, для которого он был вызван. Следовательно, этот метод блокирует выполнение вызывающего потока до тех пор, пока не станет доступным указанный Mutex. Данный метод всегда возвращает логическое значение true. Форма объявления метода WaitOne():

Mutex mutex = new Mutex(false);

mutex.WaitOne();

Когда в коде не требуется использовать Mutex, он освобождается с помощью метода ReleaseMutex():

mutex.ReleaseMutex();

Ниже продемонстрирован код реализующий работу Mutex:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

namespace Mutext

{

class Program

{

private static Mutex mut = new Mutex();

private const int numIterations = 1;

private const int numThreads = 3;

private static void Main(string[] args)

{

// Создаем потоки, которые будут использовать защищенный ресурс

for (int i = 0; i < numThreads; i++)

{

Thread myThread = new Thread(new ThreadStart(MyThreadProc));

myThread.Name = String.Format("Поток{0}", i + 1);

myThread.Start();

}

// Главный поток завершил работу

}

private static void MyThreadProc()

{

for (int i = 0; i < numIterations; i++)

{

UseResource();

}

}

//Синхронизируем данный метод

private static void UseResource()

{

mut.WaitOne();

Console.WriteLine("{0} зашел в защищенную зону",

Thread.CurrentThread.Name);

// Имитируем работу

Thread.Sleep(500);

Console.WriteLine("{0} покинул защищенную зону",

Thread.CurrentThread.Name);

// Release the Mutex.

mut.ReleaseMutex();

Console.ReadLine();

}

}}

Результат работы программы, с использованием Mutex, представлен на Рис. 5.5.

увеличить изображение Рис. 5.5. Результат выполнения программы с использованием синхронизации Mutex

Если же закомментировать методы WaitOne() и ReleaseMutex() и запустить программу, то программа сгенерирует результат, представленный на Рис. 5.6.

увеличить изображение Рис. 5.6. Результат выполнения программы без использования синхронизации Mutex

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]