Как отменить фоновый воркер со сном?

У меня проблемы с отменой фонового рабочего, в котором есть Thread.Sleep(100).

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
        int count;
        try
        {
            count = int.Parse(textBox3.Text);

            for (int i = 0; i < count; i++)
            {
                backgroundWorker1.ReportProgress((int)(((double)(i + 1) / count) * 1000));
                //Computation code
                Thread.Sleep(int.Parse(textBox4.Text));
            }
        }
        catch (Exception ex)
        {
            request.DownloadData(url);
            MessageBox.Show(ex.Message);
        }
}

private void cancel_Click(object sender, EventArgs e)
{
    backgroundWorker1.CancelAsync();
    progressBar1.Value = 0;
}

Если я удалю Thread.Sleep(100), отмена будет работать, но в противном случае она просто продолжит работу (индикатор выполнения не останавливается).

РЕДАКТИРОВАТЬ: добавлен остальной код


person Jack    schedule 14.10.2011    source источник
comment
Вы можете опубликовать оставшуюся часть цикла? Проверяет ли он какой-нибудь флаг на каждой итерации? Решает ли проблему сокращение времени сна, скажем, до 1?   -  person Joey    schedule 14.10.2011
comment
что Sleep (100) находится в цикле обработки?   -  person Renatas M.    schedule 14.10.2011
comment
Неполный код. Только вызов Sleep (100) мог лишь немного задержать отмену. Должно быть что-то еще.   -  person Henk Holterman    schedule 14.10.2011
comment
Был похожий вопрос по stackoverflow. См. stackoverflow.com/questions/800767/ < / а>   -  person wlf84k    schedule 14.10.2011
comment
Что ж, единственное, что я добавил, это поместил Sleep (100) в пробную версию.   -  person Jack    schedule 14.10.2011
comment
Ой. Вы не можете получить доступ к текстовым полям из DoWork, и ваше основное действие находится в ловушке? И в DoWork нет поддержки отмены.   -  person Henk Holterman    schedule 16.10.2011


Ответы (2)


Когда вы вызываете CancelAsync, он просто устанавливает для свойства CancellationPending значение true. Теперь ваш backgroundworker может и должен периодически проверять, установлен ли этот флаг, чтобы корректно завершить свою работу. Поэтому вам нужно разделить фоновую задачу на части, где вы можете проверить отмену.

private void DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        while(true)
        {
            if(worker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            Thread.Sleep(100);
        }
    }
person dowhilefor    schedule 14.10.2011
comment
+1 Однако это не объясняет, как работал без Thread.Sleep. - person Joey; 14.10.2011
comment
@Joey - Да, конечно. Мы не знаем, что на самом деле делал цикл. - person Security Hound; 14.10.2011

Используйте Thread.Interrupt для выхода из состояния WaitSleepJoin, если вы хотите отменить фоновый поток.

http://msdn.microsoft.com/en-us/library/system.threading.thread.interrupt.aspx

person mircea    schedule 14.10.2011
comment
Я думаю, что прерывать поток - это плохо, если есть более изящный способ (например, с использованием worker.CacellationPending). - person Joey; 14.10.2011
comment
Thread.Interrupt - это просто выход из состояния сна, когда вы хотите отменить. После этого вы перехватываете ThreadInterruptedException и проверяете наличие CancellationPending. - person mircea; 14.10.2011
comment
Я бы предпочел сделать сон короче, чтобы вам не нужно было беспокоиться о том, чтобы поймать ThreadInterruptedException. - person Joey; 14.10.2011