メソッドに関するMSDNの記事にBackgroundWorker.CancelAsync
は、次のような注意があります。
DoWork
イベント ハンドラーのコードは、キャンセル リクエストが行われているときに作業を終了する可能性があり、ポーリング ループがtrueCancellationPending
に設定されない可能性があることに注意してください。この場合、キャンセル リクエストが行われたとしても、イベント ハンドラのフラグは trueに設定されません。この状況は 競合状態と呼ばれ、マルチスレッド プログラミングでは一般的な問題です。Cancelled
System.ComponentModel.RunWorkerCompletedEventArgs
RunWorkerCompleted
この競合状態を回避するための正しい解決策は何ですか?
これは、この状態の外観を引き起こす私のサンプルコードです。
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; }
}
}