using System;
using System.ComponentModel ;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Reflection;
using Retriever.Interface;
namespace Retriever
{
class Program
{
static IRetriever cls;
static void Main(string[] args)
{
cls = new RetrieverMainClass();
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
Console.WriteLine("Press ENTER to exit...");
Console.ReadLine();
bw.CancelAsync();
Thread.Sleep(5000);
}
static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled )
cls.Suspend ();
}
static void bw_DoWork(object sender, DoWorkEventArgs e)
{
foreach (string s in cls.GetURLS())
Console.WriteLine(s);
}
}
}
Если нажать ENTER, то bw_RunWorkerCompleted не вызовется. Почему?
Здравствуйте, senglory, Вы писали:
S>Здравствуйте, bxt, Вы писали:
bxt>>Здравствуйте, senglory, Вы писали:
S>>>[c#] S>>>using System; S>>>using System.ComponentModel ;
S>Исключено. GetURLS() — это минут на 10 вызов, а я рву сразу как т-ко увижу "Press ENTER"
Здравствуйте, bxt, Вы писали:
bxt>Здравствуйте, senglory, Вы писали:
S>>Здравствуйте, bxt, Вы писали:
bxt>>>Здравствуйте, senglory, Вы писали:
S>>>>[c#] S>>>>using System; S>>>>using System.ComponentModel ;
S>>Исключено. GetURLS() — это минут на 10 вызов, а я рву сразу как т-ко увижу "Press ENTER"
bxt>Чудес не бывает
Но тут именно что непонятная хрень АКА чудо. Проверял 100 раз, GetURLS() работает долго и никаких исключений он не бросает.
Здравствуйте, senglory, Вы писали:
S>Здравствуйте, bxt, Вы писали:
bxt>>Здравствуйте, senglory, Вы писали:
S>>>Здравствуйте, bxt, Вы писали:
bxt>>>>Здравствуйте, senglory, Вы писали:
S>>>>>
S>>>>>using System;
S>>>>>using System.ComponentModel ;
S>>>Исключено. GetURLS() - это минут на 10 вызов, а я рву сразу как т-ко увижу "Press ENTER"
bxt>>Чудес не бывает :)
S>Но тут именно что непонятная хрень АКА чудо. Проверял 100 раз, GetURLS() работает долго и никаких исключений он не бросает.
Заменил bw_DoWork()
на
[c#]
static void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10000; i++)
{
Thread.Sleep(100);
Console.WriteLine(i);
}
}
Здравствуйте, senglory, Вы писали:
S>Если нажать ENTER, то bw_RunWorkerCompleted не вызовется. Почему?
Возможно я знаю в чем фишка.
Попробу-ка переписать main так:
static void Main(string[] args)
{
Thread th = new Thread(delegate(){
cls = new RetrieverMainClass();
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
Console.WriteLine("Press ENTER to exit...");
Console.ReadLine();
bw.CancelAsync();
Thread.Sleep(5000);
});
th.Start();
th.Join();
}
Если сработает ответ такой (большое ИМХО) — событие RunWorkerCompleted не файрится потому что оно хитро выполняется только на главном UIном треде, а если воркер сам на нем, то ты можешь все обновления UI делать из ProgressChanged и DoWork и RunWorkerCompleted вызван не будет.
Здравствуйте, indusov.net, Вы писали:
IN>Здравствуйте, senglory, Вы писали:
S>>Если нажать ENTER, то bw_RunWorkerCompleted не вызовется. Почему?
IN>Возможно я знаю в чем фишка. IN>Попробу-ка переписать main так:
IN>
IN> static void Main(string[] args)
IN> {
IN> Thread th = new Thread(delegate(){
IN> cls = new RetrieverMainClass();
IN> BackgroundWorker bw = new BackgroundWorker();
IN> bw.WorkerSupportsCancellation = true;
IN> bw.DoWork += new DoWorkEventHandler(bw_DoWork);
IN> bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
IN> bw.RunWorkerAsync();
IN> Console.WriteLine("Press ENTER to exit...");
IN> Console.ReadLine();
IN> bw.CancelAsync();
IN> Thread.Sleep(5000);
IN> });
IN> th.Start();
IN> th.Join();
IN> }
IN>
IN>Если сработает ответ такой (большое ИМХО) — событие RunWorkerCompleted не файрится потому что оно хитро выполняется только на главном UIном треде, а если воркер сам на нем, то ты можешь все обновления UI делать из ProgressChanged и DoWork и RunWorkerCompleted вызван не будет.
Не помогло, увы ЧТо за фигня с этим BackgroundWorker
Здравствуйте, indusov.net, Вы писали:
IN>Если сработает ответ такой (большое ИМХО) — событие RunWorkerCompleted не файрится потому что оно хитро выполняется только на главном UIном треде
Поток обработки UI-событий здесь совершенно не при делах. Вызов RunWorkerCompleted происходит через ThreadPool.QueueUserWorkItem()
Здравствуйте, senglory, Вы писали:
S>Если нажать ENTER, то bw_RunWorkerCompleted не вызовется. Почему?
Потому что размещение вызова RunWorkerCompleted происходит после того как отработает DoWork. А так как, по Вашим словам, он парит голову ажно 10 минут, и кнопку Вы жмёте сразу, то, естественно, никакого RunWorkerCompleted Вы не увидите, бо приложение уже завершилось.
Здравствуйте, drol, Вы писали:
D>Здравствуйте, senglory, Вы писали:
S>>Если нажать ENTER, то bw_RunWorkerCompleted не вызовется. Почему?
D>Потому что размещение вызова RunWorkerCompleted происходит после того как отработает DoWork. А так как, по Вашим словам, он парит голову ажно 10 минут, и кнопку Вы жмёте сразу, то, естественно, никакого RunWorkerCompleted Вы не увидите, бо приложение уже завершилось.
Если посмотреть WorkerThreadStart, который проскакивал тут ранее, видно что this.asyncOperation.PostOperationCompleted(this.operationCompleted, arg) вызывается при любом раскладе, даже если произошла ошибка.
Здравствуйте, indusov.net, Вы писали:
IN>Здравствуйте, drol, Вы писали:
D>>Здравствуйте, senglory, Вы писали:
S>>>Если нажать ENTER, то bw_RunWorkerCompleted не вызовется. Почему?
Вот до студии доберусь и сразу скажу где собак зарыт, гадать надоело.
Здравствуйте, drol, Вы писали:
D>Здравствуйте, indusov.net, Вы писали:
IN>>Если сработает ответ такой (большое ИМХО) — событие RunWorkerCompleted не файрится потому что оно хитро выполняется только на главном UIном треде D>Поток обработки UI-событий здесь совершенно не при делах. Вызов RunWorkerCompleted происходит через ThreadPool.QueueUserWorkItem()
Сорри, имелся ввиду тред на котором Main выполняется.
Здравствуйте, indusov.net, Вы писали:
IN>Если посмотреть WorkerThreadStart, который проскакивал тут ранее, видно что this.asyncOperation.PostOperationCompleted(this.operationCompleted, arg) вызывается при любом раскладе, даже если произошла ошибка.
Он вызывается после отработки DoWork. У топикстартера же DoWork работает 10 минут, а приложение завершается уже через 5 секунд. При завершении все background-потоки CLR тупо пристреливает. Причём тут какие-то ошибки ???
Здравствуйте, drol, Вы писали:
D>Здравствуйте, indusov.net, Вы писали:
IN>>Сорри, имелся ввиду тред на котором Main выполняется.
D>Легче не стало Главный поток приложения никакого отношения к ThreadPool'у также не имеет.
Здравствуйте, drol, Вы писали:
D>Здравствуйте, indusov.net, Вы писали:
IN>>Если посмотреть WorkerThreadStart, который проскакивал тут ранее, видно что this.asyncOperation.PostOperationCompleted(this.operationCompleted, arg) вызывается при любом раскладе, даже если произошла ошибка.
D>Он вызывается после отработки DoWork. У топикстартера же DoWork работает 10 минут, а приложение завершается уже через 5 секунд. При завершении все background-потоки CLR тупо пристреливает. Причём тут какие-то ошибки ???
При завершении чего?
Он канселит обработку, после чего должен вызваться RunWorkerCompleted.
MSDN: Occurs when the background operation has completed, has been canceled, or has raised an exception.
Операция BackgroundWorker-а сама собой прервана быть не может. Корректный код приведен ниже. Если нужна более подробная информация, можно почитать Прерывание операции в BackgroundWorker.
var bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += (o, e) =>
{
Console.WriteLine("{0}: Starting long running task",
DateTime.Now.TimeOfDay);
//Doing long running taskfor (int i = 0; i < 10; i++)
{
//We can split our task in multiple stages
Thread.Sleep(TimeSpan.FromSeconds(1));
bw.ReportProgress((i + 1) * 10);
if (bw.CancellationPending)
{
//user canceled our task
Console.WriteLine("{0}: Task cancelled",
DateTime.Now.TimeOfDay);
break;
}
}
Console.WriteLine("{0}: Finishing long running task",
DateTime.Now.TimeOfDay);
};
bw.ProgressChanged += (o, e) =>
{
//Processing progress
Console.WriteLine("{0}: Progress changed. Percentage: {1}",
DateTime.Now.TimeOfDay, e.ProgressPercentage);
};
bw.RunWorkerCompleted += (o, e) =>
{
//Handling worker complete eventif (e.Cancelled)
Console.WriteLine("{0}: Long running task cancelled",
DateTime.Now.TimeOfDay);
else if (e.Error != null)
Console.WriteLine("{0}: Long running task failed. Error: {1}",
DateTime.Now.TimeOfDay, e.Error);
else
Console.WriteLine("{0}: Long running task finished successfully",
DateTime.Now.TimeOfDay);
};
//Starting long running task
bw.RunWorkerAsync();
Console.ReadLine();
//If we still running our task, trying to cancel itif (bw.IsBusy)
bw.CancelAsync();
Console.ReadLine();
Здравствуйте, indusov.net, Вы писали:
IN>>>Сорри, имелся ввиду тред на котором Main выполняется.
D>>Легче не стало Главный поток приложения никакого отношения к ThreadPool'у также не имеет.
IN>!пт, инстанс BackgroundWorker где создан?
А какая разница ??? DoWork запускается через BeginInvoke() его типа-делегата. RunWorkerCompleted через ThreadPool. Причём тут поток создатель BackgroundWorker'а ???
IN>P.S. Может я витиевато изъясняюсь. Забей.
Здравствуйте, indusov.net, Вы писали:
IN>При завершении чего?
При завершении приложения.
IN>Он канселит обработку, после чего должен вызваться RunWorkerCompleted.
Cancelling в BackgroundWorker'е — всего лишь взведение соответствующего флажка. Исполнение DoWork никто не прерывает. Если хочется реального cancelling'а, то его нужно делать ручками в DoWork. Ничего подобного в коде топикстартера не наблюдается — его DoWork будет молотить до победы.
Здравствуйте, drol, Вы писали:
D>Вы просто не понимаете как работает механизма.
Чукча не читатель, чукча писатель.
Re[6]: Почему не срабатывает RunWorkerCompleted?
От:
Аноним
Дата:
05.08.09 10:21
Оценка:
Здравствуйте, drol, Вы писали:
D>Здравствуйте, indusov.net, Вы писали:
IN>>При завершении чего? D>При завершении приложения. IN>>Он канселит обработку, после чего должен вызваться RunWorkerCompleted. D>Cancelling в BackgroundWorker'е — всего лишь взведение соответствующего флажка. Исполнение DoWork никто не прерывает. Если хочется реального cancelling'а, то его нужно делать ручками в DoWork. Ничего подобного в коде топикстартера не наблюдается — его DoWork будет молотить до победы.
Да, 15 секунд отладки кода топикстартера показали твою правоту
После CancelAsync мы успешно продолжаем приходить в DoWork.
Здравствуйте, drol, Вы писали:
D>Cancelling в BackgroundWorker'е — всего лишь взведение соответствующего флажка. Исполнение DoWork никто не прерывает. Если хочется реального cancelling'а, то его нужно делать ручками в DoWork. Ничего подобного в коде топикстартера не наблюдается — его DoWork будет молотить до победы.
Да, 15 секунд отладки кода топикстартера показали твою правоту
После CancelAsync мы успешно продолжаем приходить в DoWork.
Вот только как бы сделать уведомление о прерывании треда, если тред исполняет одну долгоиграющую функцию, к-рая не может ничего знать о CancellationPending и пр. деталях ее вызова? Не важно , как это сделать — без BackgroundWorker или с ним.
Здравствуйте, senglory, Вы писали:
S>Вот только как бы сделать уведомление о прерывании треда, если тред исполняет одну долгоиграющую функцию, к-рая не может ничего знать о CancellationPending и пр. деталях ее вызова? Не важно , как это сделать — без BackgroundWorker или с ним.
Еще раз повторюсь. Почитай здесь. Здесь же именно твой случай и расписывается.
public class AbortableBackgroundWorker : BackgroundWorker
{
private Thread workerThread;
protected override void OnDoWork(DoWorkEventArgs e)
{
workerThread = Thread.CurrentThread;
try
{
base.OnDoWork(e);
}
catch (ThreadAbortException)
{
e.Cancel = true; //We must set Cancel property to true!
Thread.ResetAbort(); //Prevents ThreadAbortException propagation
}
}
public void Abort()
{
if (workerThread != null)
{
workerThread.Abort();
workerThread = null;
}
}
}
Основная работа делается в переопределенном методе OnDoWork, который уже вызывается в потоке пула потоков (т.к. реализация класса BackgroundWorker основана на пуле потоков). В этом методе запоминается поток, выполняющий текущую операцию, и в методе Abort вызывается метод Abort этого потока.
Прерывание потока путем вызова метода Thread.Abort имеет некоторые особенности, которые нужно учитывать, как при реализации класса AbortableBackgroundWorker, так и его клиентов. Исключение ThreadAbortException является особенным типом исключения, которое трактуется CLR особым образом. Основная особенность в том, что после выполнения блоков catch и finally никакой код выполняться не будет, а учитывая, что прерываемый поток является потоком из пула потоков, то ни к чему хорошему это не приведет. Именно поэтому в обработчике исключения ThreadAbortException метода OnDoWork вызывается метод Thread.ResetAbort, который предотвращает распространение исключения ThreadAbortException и выполнения потока продолжается, но уже не с того места, где он выполнялся (в середине длительной операции), а так, как будто асинхронная операция успешно завершилась.
На клиентов класса AbortableBackgroundWorker, также налагаются некоторые ограничения, связанной с прерыванием рабочего потока. Во-первых, если обработчик события DoWork содержит обработку исключения, то там должно быть дополнительный блок catch для исключения ThreadAbortException, который обрабатывать на этом уровне не нужно. Во-вторых, исключение ThreadAbortException относится к асинхронным исключениями, которые могут возникнуть в любой точке управляемого кода, что может привести к непредвиденным последствиям и рассогласованному состоянию приложения. Например, если будет прерван поток, выполняющий статический конструктор некоторого класса, то последующее обращение к этому классу также будет приводить к генерации исключения TypeLoadException. В-третьих, CLR не всегда сможет прервать выполнение потока. Так, например, прерывание потока будет невозможно, если поток выполняет неуправляемый код или блоки catch/finally управляемого кода.