Книга: C# 4.0: полное руководство
Взаимоблокировка и состояние гонки
Взаимоблокировка и состояние гонки
При разработке многопоточных программ следует быть особенно внимательным, чтобы избежать взаимоблокировки и состояний гонок. Взаимоблокировка, как подразумевает само название, — это ситуация, в которой один поток ожидает определенных действий от другого потока, а другой поток, в свою очередь, ожидает чего-то от первого потока. В итоге оба потока приостанавливаются, ожидая друг друга, и ни один из них не выполняется. Эта ситуация напоминает двух слишком вежливых людей, каждый из которых настаивает на том, чтобы другой прошел в дверь первым!
На первый взгляд избежать взаимоблокировки нетрудно, но на самом деле не все так просто, ведь взаимоблокировка может возникать окольными путями. В качестве примера рассмотрим класс TickTock
из предыдущей программы. Как пояснялось выше, в отсутствие завершающего вызова метода Pulse()
из метода Tick()
или Tock()
тот или другой будет ожидать до бесконечности, что приведет к "зависанию" программы вследствие взаимоблокировки. Зачастую причину взаимоблокировки не так-то просто выяснить, анализируя исходный код программы, поскольку параллельно действующие процессы могут взаимодействовать довольно сложным образом во время выполнения. Для исключения взаимоблокировки требуется внимательное программирование и тщательное тестирование. В целом, если многопоточная программа периодически "зависает", то наиболее вероятной причиной этого является взаимоблокировка.
Состояние гонки возникает в том случае, когда два потока или больше пытаются одновременно получить доступ к общему ресурсу без должной синхронизации. Так, в одном потоке может сохраняться значение в переменной, а в другом — инкрементироваться текущее значение этой же переменной. В отсутствие синхронизации конечный результат будет зависеть от того, в каком именно порядке выполняются потоки: инкрементируется ли значение переменной во втором потоке или же оно сохраняется в первом. О подобной ситуации говорят, что потоки "гоняются друг за другом", причем конечный результат зависит от того, какой из потоков завершится первым. Возникающее состояние гонок, как и взаимоблокировку, непросто обнаружить. Поэтому его лучше предотвратить, синхронизируя должным образом доступ к общим ресурсам при программировании.
- Основы многопоточной обработки
- Класс Thread
- Определение момента окончания потока
- Передача аргумента потоку
- Свойство IsBackground
- Приоритеты потоков
- Синхронизация
- Сообщение между потоками с помощью методов Wait(), Pulse() и PulseAll()
- Взаимоблокировка и состояние гонки
- Применение атрибута MethodlmplAttribute
- Применение мьютекса и семафора
- Применение событий
- Класс Interlocked
- Классы синхронизации, внедренные в версии .NET Framework 4.0
- Прерывание потока
- Приостановка и возобновление потока
- Определение состояния потока
- Применение основного потока
- Дополнительные средства многопоточной обработки, внедренные в версии .NET Framework 4.0
- Рекомендации по многопоточному программированию
- Запуск отдельной задачи