В MSDN article о BackgroundWorker.CancelAsync
метода, есть предостережение, которое говорит:Как избежать состояния гонки при использовании BackgroundWorker.CancelAsync?
Имейте в виду, что ваш код в обработчик
DoWork
событий может закончить свою работу как запрос на отмену делается, и ваш цикл опроса может миссияCancellationPending
установлен на true. В этом случае,Cancelled
флагSystem.ComponentModel.RunWorkerCompletedEventArgs
в обработчике событияRunWorkerCompleted
не будет установлен в истинной, даже , хотя запрос на аннулирование было сделано. Эта ситуация называется Состояние гонки и является общей проблемой при многопоточном программировании.
Какое правильное и правильное решение, чтобы избежать этого Состояние гонки?
Вот мой пример кода, который провоцирует Apperance этого условия:
public partial class MainWindow : Window
{
BackgroundWorker bW;
int bWsCount = 0;
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (bW != null)
bW.CancelAsync();
bW = new BackgroundWorker();
bW.WorkerSupportsCancellation = true;
bW.DoWork += new DoWorkEventHandler(bW_DoWork);
bW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bW_RunWorkerCompleted);
bW.RunWorkerAsync(0);
bWsCount++;
labelBackgroundWorkersCount.Content = bWsCount;
}
void bW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (e.Cancelled || worker.CancellationPending)
{
bWsCount--;
labelBackgroundWorkersCount.Content = bWsCount;
}
else
worker.RunWorkerAsync(1000);
}
void bW_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int sleepDuration = Convert.ToInt32(e.Argument);
if (worker.CancellationPending) { e.Cancel = true; return; }
Thread.Sleep(sleepDuration);
if (worker.CancellationPending) { e.Cancel = true; return; }
}
}
Спасибо за разъяснение! :) – Matvienko
Мне нравится этот ответ. Однако, не является ли исходный код по существу этим, проверяя «worker.CancellationPending»? Пока 'CancelAsync' только когда-либо вызывается в потоке ui, а' worker.CancellationPending' проверяется на нитке ui, вы избегаете условия гонки. Правильно? –
@Matt - CancellationPending сбрасывается до запуска RunWorkerCompleted. –