- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания C# 4.0: полное руководство - Герберт Шилдт
Шрифт:
Интервал:
Закладка:
Monitor.Wait(lockOn); // ожидать завершения метода Tock()
}
}
public void Tock(bool running) {
lock(lockOn) {
if(!running) { // остановить часы
Monitor.Pulse(lockOn); // уведомить любые ожидающие потоки
return;
}
Console.WriteLine("так");
Monitor.Pulse(lockOn); // разрешить выполнение метода Tick()
Monitor.Wait(lockOn); // ожидать завершения метода 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 mt1 = new MyThread("Tick", tt);
MyThread mt2 = new MyThread("Tock", tt);
mt1.Thrd.Join();
mt2.Thrd.Join();
Console.WriteLine("Часы остановлены");
}
}
Ниже приведен результат выполнения этой программы.
тик так
тик так
тик так
тик так
тик так
Часы остановлены
Рассмотрим эту программу более подробно. В методе Main() создается объект tt типа TickTock, который используется для запуска двух потоков на выполнение. Если в методе Run() из класса MyThread обнаруживается имя потока Tick, соответствующее ходу часов "тик", то вызывается метод Tick(). А если это имя потока Tock, соответствующее ходу часов "так", то вызывается метод Tock(). Каждый из этих методов вызывается пять раз подряд с передачей логического значения true в качестве аргумента. Часы идут до тех пор, пока этим методам передается логическое значение true, и останавливаются, как только передается логическое значение false.
Самая важная часть рассматриваемой здесь программы находится в методах Tick() и Tock(). Начнем с метода Tick(), код которого для удобства приводится ниже.
public void Tick(bool running) {
lock(lockOn) {
if(!running) { // остановить часы
Monitor.Pulse(lockOn); // уведомить любые ожидающие потоки
return;
}
Console.Write("тик ");
Monitor.Pulse(lockOn); // разрешить выполнение метода Tock()
Monitor.Wait(lockOn); // ожидать завершения метода Tock()
}
}
Прежде всего обратите внимание на код метода Tick() в блоке lock. Напомним, что методы Wait() и Pulse() могут использоваться только в синхронизированных блоках кода. В начале метода Tick() проверяется значение текущего параметра, которое служит явным признаком остановки часов. Если это логическое значение false, то часы остановлены. В этом случае вызывается метод Pulse(), разрешающий выполнение любого потока, ожидающего своей очереди. Мы еще вернемся к этому моменту в дальнейшем. Если же часы идут при выполнении метода Tick(), то на экран выводится слово "тик" с пробелом, затем вызывается метод Pulse(), а после него — метод Wait(). При вызове метода Pulse() разрешается выполнение потока для того же самого объекта, а при вызове метода Wait() выполнение метода Tick() приостанавливается до тех пор, пока метод Pulse() не будет вызван из другого потока. Таким образом, когда вызывается метод Tick(), отображается одно слово "тик" с пробелом, разрешается выполнение другого потока, а затем выполнение данного метода приостанавливается.
Метод Тоск() является точной копией метода Tick(), за исключением того, что он выводит на экран слово "так". Таким образом, при входе в метод Тоск() на экран выводится слово "так", вызывается метод Pulse(), а затем выполнение метода Тоск() приостанавливается. Методы Tick() и Тоск() можно рассматривать как поочередно сменяющие друг друга, т.е. они взаимно синхронизированы.
Когда часы остановлены, метод Pulse() вызывается для того, чтобы обеспечить успешный вызов метода Wait(). Напомним, что метод Wait() вызывается в обоих методах, Tick() и Тоск(), после вывода соответствующего слова на экран. Но дело в том, что когда часы остановлены, один из этих методов все еще находится в состоянии ожидания. Поэтому завершающий вызов метода Pulse() требуется, чтобы выполнить ожидающий метод до конца. В качестве эксперимента попробуйте удалить этот вызов метода Pulse() и понаблюдайте за тем, что при этом произойдет. Вы сразу же обнаружите, что программа "зависает", и для выхода из нее придется нажать комбинацию клавиш <Ctrl+C>. Дело в том, что когда метод Wait() вызывается в последнем вызове метода Тоск(), соответствующий ему метод Pulse() не вызывается, а значит, выполнение метода Тоск() оказывается незавершенным, и он ожидает своей очереди до бесконечности.
Прежде чем переходить к чтению следующего раздела, убедитесь сами, если, конечно, сомневаетесь, в том, что следует обязательно вызывать методы Wait() и Pulse(), чтобы имитируемые часы шли правильно. Для этого подставьте приведенный ниже вариант класса TickTock в рассматриваемую здесь программу. В этом варианте все вызовы методов Wait() и Pulse() исключены.
// Нерабочий вариант класса TickTock.
class TickTock {
object lockOn = new object();
public void Tick(bool running) {
lock(lockOn) {
if (!running) { // остановить часы
return;
}
Console.Write("тик ") ;
}
}
public void Tock (bool running) {
lock(lockOn) {
if(!running) { // остановить часы
return;
}
Console.Write("так ") ;
}
}
}
После этой подстановки результат выполнения данной программы будет выглядеть следующим образом.
тик так так так так так тик тик тик тик Часы остановлены
Очевидно, что методы Tick() и Tock() больше не синхронизированы!
Взаимоблокировка и состояние гонки
При разработке многопоточных программ следует быть особенно внимательным, чтобы избежать взаимоблокировки и состояний гонок. Взаимоблокировка, как подразумевает само название, — это ситуация, в которой один поток ожидает определенных действий от другого потока, а другой поток, в свою очередь, ожидает чего-то от первого потока. В итоге оба потока приостанавливаются, ожидая друг друга, и ни один из них не выполняется. Эта ситуация напоминает двух слишком вежливых людей, каждый из которых настаивает на том, чтобы другой прошел в дверь первым!
На первый взгляд избежать взаимоблокировки нетрудно, но на самом деле не все так просто, ведь взаимоблокировка может возникать окольными путями. В качестве примера рассмотрим класс TickTock из предыдущей программы. Как пояснялось выше, в отсутствие завершающего вызова метода Pulse() из метода Tick() или Tock() тот или другой будет ожидать до бесконечности, что приведет к "зависанию" программы вследствие взаимоблокировки. Зачастую причину взаимоблокировки не так-то просто выяснить, анализируя исходный код программы, поскольку параллельно действующие процессы могут взаимодействовать довольно сложным образом во время выполнения. Для исключения взаимоблокировки требуется внимательное программирование и тщательное тестирование. В целом, если многопоточная программа периодически "зависает", то наиболее вероятной причиной этого является взаимоблокировка.