- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
C# 4.0 полное руководство - 2011 - Герберт Шилдт
Шрифт:
Интервал:
Закладка:
тик тик тик тик тик так
так
так
так
так
Часы остановлены
Очевидно, что методы Tick () и Tock () больше не синхронизированы!
Взаимоблокировка и состояние гонки
При разработке многопоточных программ следует быть особенно внимательным, чтобы избежать взаимоблокировки и состояний гонок. Взаимоблокировка, как подразумевает само название, — это ситуация, в которой один поток ожидает определенных действий от другого потока, а другой поток, в свою очередь, ожидает чего-то от первого потока. В итоге оба потока приостанавливаются, ожидая друг друга, и ни один из них не выполняется. Эта ситуация напоминает двух слишком вежливых людей, каждый из которых настаивает на том, чтобы другой прошел в дверь первым!
На первый взгляд избежать взаимоблокировки нетрудно, но на самом деле не все так просто, ведь взаимоблокировка может возникать окольными путями. В качестве примера рассмотрим класс TickTock из предыдущей программы. Как пояснялось выше, в отсутствие завершающего вызова метода Pulse () из метода Tick () или Tock () тот или другой будет ожидать до бесконечности, что приведет к "зависанию" программы вследствие взаимоблокировки. Зачастую причину взаимоблокировки не так-то просто выяснить, анализируя исходный код программы, поскольку параллельно действующие процессы могут взаимодействовать довольно сложным образом во время выполнения. Для исключения взаимоблокировки требуется внимательное программирование и тщательное тестирование. В целом, если многопоточная программа периодически "зависает", то наиболее вероятной причиной этого является взаимоблокировка.
Состояние гонки возникает в том случае, когда два потока или больше пытаются одновременно получить доступ к общему ресурсу без должной синхронизации. Так, в одном потоке может сохраняться значение в переменной, а в другом — инкрементироваться текущее значение этой же переменной. В отсутствие синхронизации конечный результат будет зависеть от того, в каком именно порядке выполняются потоки: инкрементируется ли значение переменной во втором потоке или же оно сохраняется в первом. О подобной ситуации говорят, что потоки "гоняются друг за другом", причем конечный результат зависит от того, какой из потоков завершится первым. Возникающее состояние гонок, как и взаимоблокировку, непросто обнаружить. Поэтому его лучше предотвратить, синхронизируя должным образом доступ к общим ресурсам при программировании.
Применение атрибута MethodlmplAttribute
Метод может быть полностью синхронизирован с помощью атрибута MethodlmplAttribute. Такой подход может стать альтернативой оператору lock в тех случаях, когда метод требуется заблокировать полностью. Атрибут
MethodlmplAttгibute определен в пространстве имен System . Runtime . CompilerServices. Ниже приведен конструктор, применяемый для подобной синхронизации:
public MethodlmplAttribute(MethodlmplOptions methodlmplOptions)
где methodlmplOptions обозначает атрибут реализации. Для синхронизации метода достаточно указать атрибут MethodlmplOptions. Synchronized. Этот атрибут вызывает блокировку всего метода для текущего экземпляра объекта, доступного по ссылке this. Если же метод относится к типу static, то блокируется его тип. Поэтому данный атрибут непригоден для применения в открытых объектах или классах.
Ниже приведена еще одна версия программы, имитирующей тиканье часов, с переделанным вариантом класса TickTock, в котором атрибут MethodlmplOptions обеспечивает должную синхронизацию.
// Использовать атрибут MethodlmplAttribute для синхронизации метода.
using System;
using System.Threading;
using System.Runtime.CompilerServices;
// Вариант класса TickTock, переделанный с целью // использовать атрибут MethodlmplOptions.Synchronized, class TickTock {
/* Следующий атрибут полностью синхронизирует метод Tick(). */ [MethodlmplAttribute(MethodlmplOptions.Synchronized)] public void Tick (bool running) { if(!running) { // остановить часы
Monitor.Pulse(this); // уведомить любые ожидающие потоки return;
}
Console.Write("тик ");
Monitor.Pulse(this); // разрешить выполнение метода Tock()
Monitor.Wait(this); // ожидать завершения метода Tock()
}
/* Следующий атрибут полностью синхронизирует метод Тоск(). */ [MethodlmplAttribute(MethodlmplOptions.Synchronized)] public void Tock(bool running) { if (!running) { // остановить часы
Monitor.Pulse(this); // уведомить любые ожидающие потоки return;
}'
Console.WriteLine("так");
Monitor.Pulse(this); // разрешить выполнение метода Tick()
Monitor.Wait(this); // ожидать завершения метода Tick()
}
}
class MyThread {
public Thread Thrd;
TickTock ttOb;
// Сконструировать новый поток.
public MyThread(string name, TickTock tt) {
Thrd = new Thread(this.Run); ttOb = tt;
Thrd.Name = name;
Thrd.Start();
}
// Начать выполнение нового потока, void Run() {
if(Thrd.Name == "Tick") {
for(int i=0; i<5; i++) ttOb.Tick(true); ttOb.Tick(false);
}
else {
for(int i=0; i<5; i++) ttOb.Tock(true); ttOb.Tock(false);
}
}
}
class TickingClock { static void Main() {
TickTock tt = new TickTock();
MyThread mtl = new MyThread("Tick", tt) ;
MyThread mt2 = new MyThread("Tock", tt) ;
mtl.Thrd.Join(); mt2.Thrd.Join();
Console.WriteLine("Часы остановлены");
}
}
Эта версия программы дает такой же результат, как и предыдущая. Синхронизируемый метод не определен в открытом классе и не вызывается для открытого объекта, поэтому применение оператора lock или атрибута MethodlmplAttribute зависит от личных предпочтений. Ведь и тот и другой дает один и тот же результат. Но поскольку ключевое слово lock относится непосредственно к языку С#, то в примерах, приведенных в этой книге, предпочтение отдано именно ему.
ПРИМЕЧАНИЕ
Не применяйте атрибут MethodlmplAttribute в открытых классах или экземплярах открытых объектов. Вместо этого пользуйтесь оператором lock, чтобы заблокировать метод для закрытого объекта, как пояснялось ранее.
Применение мьютекса и семафора
В большинстве случаев, когда требуется синхронизация, оказывается достаточно и оператора lock. Тем не менее в некоторых случаях, как, например, при ограничении доступа к общим ресурсам, более удобными оказываются механизмы синхронизации, встроенные в среду .NET Framework. Ниже рассматриваются по порядку два таких механизма: мьютекс и семафор.
Мьютекс
Мьютекс представляет собой взаимно исключающий синхронизирующий объект. Это означает, что он может быть получен потоком только по очереди. Мьютекс предназначен для тех ситуаций, в которых общий ресурс может быть одновременно использован только в одном потоке. Допустим, что системный журнал совместно используется в нескольких процессах, но только в одном из них данные могут записываться в файл этого журнала в любой момент времени. Для синхронизации процессов в данной ситуации идеально подходит мьютекс.
Мьютекс поддерживается в классе System. Threading.Mutex. У него имеется несколько конструкторов. Ниже приведены два наиболее употребительных конструктора.
public Mutex()
public Mutex(bool initiallyOwned)
В первой форме конструктора создается мьютекс, которым первоначально никто не владеет. А во второй форме исходным состоянием мьютекса завладевает вызывающий поток, если параметр ini tiallyOwned имеет логическое значение true. В противном случае мьютексом никто не владеет.
Для того чтобы получить мьютекс, в коде программы следует вызвать метод WaitOne () для этого мьютекса. Метод WaitOne () наследуется классом Mutex от класса Thread. WaitHandle. Ниже приведена его простейшая форма.
public bool WaitOne ();
Метод WaitOne () ожидает до тех пор, пока не будет получен мьютекс, для которого он был вызван. Следовательно, этот метод блокирует выполнение вызывающего потока до тех пор, пока не станет доступным указанный мьютекс. Он всегда возвращает логическое значение true.
Когда же в коде больше не требуется владеть мьютексом, он освобождается посредством вызова метода ReleaseMutex (), форма которого приведена ниже.
public void ReleaseMutex()
В этой форме метод ReleaseMutex () освобождает мьютекс, для которого он был вызван, что дает возможность другому потоку получить данный мьютекс.

