Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка для КР по ООП.doc
Скачиваний:
8
Добавлен:
18.04.2019
Размер:
2.47 Mб
Скачать

Очередь как объект синхронизации

Достаточно сложное образование с множеством свойств и методов, предназначенное для упорядоченного размещения объектов (все дети класса object). Одновременное воздействие на очередь со стороны кода нескольких потоков представляет серьёзную опасность. И не только для самого объекта очереди в смысле возможного искажения сохраняемой в ней информации, сколько для самого приложения. Класс Queue взаимодействует с окружением через интерфейсы, неупорядоченное воздействие на объект очереди через эти интерфейсы возбуждает исключения. Очередь располагает специальными средствами, позволяющими защитить объект от неупорядоченного воздействия со стороны множества потоков. Назначение некоторых средств и их применение очевидно, как использовать другие средства – пока неясно (я пометил их вопросительным знаком).

В класс входят методы и свойства:

  • множество вариантов конструкторов - Queue(…),

  • методы, обеспечивающие загрузку и выгрузку данных (объектов-представителей классов-наследников класса object) – void Enqueue(object), object Dequeue(),

  • методы поиска – bool Contains(object),

  • методы предъявления – object Peek() (возвращает объект из начала очереди, не удаляя его из очереди),

  • свойство Count – сохраняет информацию о количестве объектов в очереди,

  • свойство SyncRoot – предоставляет ссылку на ОБЪЕКТ СИНХРОНИЗАЦИИ, который используется при синхронизации потоков многопоточного приложения,

  • свойство IsSynchronized (?) – предоставляет информацию о том, синхронизирован ли объект для работы в многопоточном приложении. Это всего лишь значение объявленной в классе Queue булевской переменной,

  • статический метод Synchronized (?) – создающий синхронизированную оболочку вокруг объекта очереди.

Примеры использования очередей в приложении приводятся ниже, а пока – вопросы, связанные с взаимодействием объекта очереди с потоками многопоточного приложения.

Перебор элементов очереди посредством оператора цикла foreach – самое “опасное” для очереди занятие в условиях многопоточного приложения. И причина всех неприятностей заключается во внутреннем устройстве и особенностях реализации цикла foreach, который при своём выполнении использует множество функций интерфейса очереди:

Queue myCollection = new Queue();

::::::::::::::::::::::::::::::::::

// Перебор элементов очереди – критическая секция кода.

foreach ( Object item in myCollection )

{

:::::::::::::::::::::::::::::::::::::::

}

Возможный способ преодоления опасной ситуации – защита кода критической секцией. Суть защиты сводится к следующему. Поток, выполняющий собственный код при “подходе” к критической секции, связанной с конкретным объектом синхронизации, блокируется, если ЭТУ или ДРУГУЮ связанную с данным объектом синхронизации критическую секцию в данное время выполняет другой поток.

Queue myCollection = new Queue();

::::::::::::::::::::::::::::::::::::::

lock( myCollection.SyncRoot )

{// Критическая секция, связанная с объетом

// синхронизации, полученным от очереди

// myCollection обозначена…

foreach ( Object item in myCollection )

{

:::::::::::::::::::::::::::::::::::::::

}

}

Пример синхронизации объекта очереди. Видно, как создавать синхронизированную оболочку вокруг несинхронизированной очереди, как узнавать о том, синхронизирована она или нет, НО ЗАЧЕМ ДЕЛАТЬ ЭТО – не сказано и не показано. Дело в том, что synchronized она или нет, а соответствующий код (критические секции кода) защищать всё равно надо!

using System;

using System.Collections;

public class SamplesQueue {

public static void Main() {

// Creates and initializes a new Queue.

Queue myQ = new Queue();

myQ.Enqueue( “The” );

myQ.Enqueue( “quick” );

myQ.Enqueue( “brown” );

myQ.Enqueue( “fox” );

// Creates a synchronized wrapper around the Queue.

Queue mySyncdQ = Queue.Synchronized( myQ );

// Displays the sychronization status of both Queues.

Console.WriteLine(“myQ is {0}.”,

myQ.IsSynchronized ? “synchronized” : “not synchronized” );

Console.WriteLine( “mySyncdQ is {0}.”,

mySyncdQ.IsSynchronized ? “synchronized” : “not synchronized” );

}

}

/*

This code produces the following output.

myQ is not synchronized.

mySyncdQ is synchronized.

*/