Как дождаться завершения BackgroundWorker, а затем выйти из консольного приложения
Я написал пример консольного приложения для тестирования фонового рабочего, используя один из примеров, размещенных здесь в Stackoverflow. У меня есть работник backgroundwork, который начинается с основного метода, но заканчивается в середине операции, если я нажимаю кнопку ввода, потому что я написал файл console.readkey в основном методе. Но я хочу, чтобы он подождал, пока фоновая работа закончит выполнение задания, а затем выйдет из приложения. Это мой код.
class Program
{
private static BackgroundWorker worker = new BackgroundWorker();
private event EventHandler BackgroundWorkFinished;
static void Main(string[] args)
{
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged += worker_ProgressChanged;
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
Console.WriteLine("Starting Application...");
worker.RunWorkerAsync();
Console.ReadKey();
}
static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Console.WriteLine(e.ProgressPercentage.ToString());
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Starting to do some work now...");
int i;
for (i = 1; i < 10; i++)
{
Thread.Sleep(1000);
worker.ReportProgress(Convert.ToInt32((100.0 * i) / 10));
}
e.Result = i;
}
static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Value Of i = " + e.Result.ToString());
Console.WriteLine("Done now...");
}
}
Ответы
Ответ 1
См. Как подождать, когда BackgroundWorker отменит? сообщение для связи между вашим BackgroundWorker и основным потоком.
В принципе, вы должны использовать событие, которое вы установили в конце DoWork, чтобы сигнализировать о завершении DoWork. Вы затем WaitOne() на этом событии в своем основном потоке.
Ответ 2
Основной целью Bgw является взаимодействие с Windows MessageQueue. Другими словами, это наиболее полезно в WinForms и WPF-приложениях.
Консольное приложение не подходит для использования или тестирования Bgw. Вы получите странные результаты. Распечатайте ManagedThreadId в ключевых точках, чтобы узнать, что произойдет.
И какой-то стандартный совет: ваш worker_RunWorkerCompleted()
должен проверить e.Error
. Сейчас это то же самое, что с пустым блоком catch{}
.Забастовкa >
Любая ошибка DoWork теперь будет брошена, когда вы прочитаете e.Result
, более сложную для обработки.
Ответ 3
Это то, что я сделал сейчас. Но console.readkey()
не работает. Приложение не ждет функции ReadKey()
.
class Program
{
private static BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
private static AutoResetEvent resetEvent = new AutoResetEvent(false);
static void Main(string[] args)
{
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged += worker_ProgressChanged;
worker.WorkerReportsProgress = true;
Console.WriteLine("Starting Application...");
worker.RunWorkerAsync();
resetEvent.WaitOne();
Console.ReadKey();
}
static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Console.WriteLine(e.ProgressPercentage.ToString());
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Starting to do some work now...");
int i;
for (i = 1; i < 10; i++)
{
Thread.Sleep(1000);
worker.ReportProgress(Convert.ToInt32((100.0 * i) / 10));
}
e.Result = i;
resetEvent.Set();
}
static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Value Of i = " + e.Result.ToString());
Console.WriteLine("Done now...");
}
}
Исправление Edit: Перемещено resetEvent.Set()
внутрь DoWork, а не в RunWorkerCompleted. Обработчик события Завершенный никогда не будет вызван, потому что главный поток ожидает события.