- •Многопоточность
- •Оглавление
- •Задачи многопоточности
- •Методы создания потоков
- •Делегаты
- •Ожидание завершения работы потока
- •Получение результата работы метода, выполнявшегося в отдельном потоке
- •Класс Thread
- •Ожидание завершения потока
- •Управление выполнением потока
- •«Сон» потока
- •Приоритет потоков
- •Фоновые потоки и потоки «переднего плана»
- •Класс ThreadPool
- •Синхронизация потоков
- •Оператор lock
- •Класс ReaderWriterLock
- •Класс Mutex
- •Класс WaitHandle
- •Класс AutoResetEvent
- •Класс ManualResetEvent
- •Блокировка потоков
- •Взаимодествие с пользовательским интерфейсом
- •Метод Invoke
- •Использование SynchronizationContext
- •Класс BackgroundWorker
- •Окончание работы и возвращение результата
- •Прогресс выполнения
- •Отмена выполнения метода
- •Объект Dispatcher
- •Класс BackgroundWorker
- •Заключение
Отмена выполнения метода
Иногда требуется прервать выполнение длительной задачи. Для этой цели класс BackgroundWorker предоставляет метод CancelAsync. Вызов данного метода приводит к выставлению в true свойства CancellationPending объекта BackgroundWorker. Программист к обработчике события DoWork может (но не обязан) проверять это свойство. Если оно истинно, программист может некоторым образом досрочно завершить работу потока. Так же он может установить в true свойство Cancel объекта DoWorkEventArgs, чтобы в обработчике события RunWorkerCompleted стало известно, что работа прервана пользователем:
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
return;
}
Вот, собственно, и все, что касается работы с классом BackgroundWorker. Его преимущество заключается в том, что он берет на себя практически всю работу по синхронизации отдельного потока с пользовательским интерфейсом. Его события прогресса и окончания работы исполняются в потоке пользовательского интерфейса, так что программист может не заботиться сам о синхронизации. Кроме того, BackgroundWorker предлагает удобные механизмы прерывания работы, уведомления о завершении, получения результатов и возникших ошибок. Поэтому при работе с GUI этот класс следует использовать везде, где только возможно.
WPF
С версии 3 .NET Framework поддерживает новую технологию для создания пользовательских интерфейсов – WPF (Windows Presentation Foundation). В принципе с точки зрения взаимодействия с многопоточностью эта технология мало чем отличается от WinForms. Точно так же изменение состояние элементов управления WPF допускается только из потока пользовательского интерфейса. Рассмотрим же существующие различия (программа ThreadingWPFSynchronization).
Объект Dispatcher
Все объекты, для которых важно то, чтобы их изменение происходило из того же потока, в котором они были созданы, являются наследниками класса DispatcherObject. Данный класс имеет два метода CheckAccess и VerifyAccess. Оба они проверяют, выполняется ли текущий код в том же потоке, в котором был создан объект. CheckAccess возвращает булевское значение, а VerifyAccess генерирует исключение, если код выполняется не в том потоке. Все элементы управления WPF унаследованы от DispatcherObject и часто используют VerifyAccess для проверки того, правильно ли производятся их изменения.
Кроме того, объект DispatcherObject имеет свойство Dispatcher, возвращающее объект Dispatcher, который можно использовать для выполнения вашего кода в потоке пользовательского интерфейса. Объект Dispatcher имеет метод Invoke, работающий совершенно так же, как и аналогичный метод элементов управления WinForms.
private long GetCheckNumber()
{
if (!this.CheckAccess())
{
Func<long> dlgt = new Func<long>(GetCheckNumber);
return (long)this.Dispatcher.Invoke(dlgt);
}
else
{
return long.Parse(tbCheckNumber.Text);
}
}
Вместо InvokeRequired вы используете CheckAccess, а метод Invoke вызываете у объекта, доступного через свойство Dispatcher. Вот и все различия.