Как ждать, пока поток завершит свою работу - PullRequest
0 голосов
/ 09 января 2009

У меня есть консольное приложение. Класс (скажем, Worker) выполняет некоторую работу в отдельном потоке и выдает событие, когда завершается. Но этого никогда не происходит, потому что выполнение заканчивается мгновенно. Как я могу дождаться окончания потока и обработать событие после того, как он выбрасывает?

static void Main(string[] args)
{
    Worker worker = new Worker();
    worker.WorkCompleted += PostProcess;
    worker.DoWork();
}

static void PostProcess(object sender, EventArgs e) { // Cannot see this happening }

Редактировать: Исправлен порядок операторов, но это не было проблемой.

Ответы [ 8 ]

15 голосов
/ 09 января 2009

У вас есть условие гонки, в котором работа может быть закончена до того, как вы зарегистрируетесь на событие. Чтобы избежать условия гонки, измените порядок кода, чтобы вы регистрировались на событие перед началом работы, тогда оно будет всегда вызываться независимо от того, как быстро оно закончится:

static void Main(string[] args)
{
    Worker worker = new Worker();
    worker.WorkCompleted += PostProcess;
    worker.DoWork();
}

Edit:

Хорошо, вопрос был изменен, поэтому похоже, что вы действительно спрашиваете, как ждать, пока PostProcess завершит выполнение. Есть несколько способов сделать это, но вам придется добавить еще немного кода.

Самый простой способ, поскольку события всегда выполняются в том же потоке, в котором они были созданы, - это вызвать Thread.Join в потоке, который создает класс Worker, например, при условии, что поток представлен как свойство:

worker.Thread.Join();

(Хотя, если честно, я бы, вероятно, оставил Thread в секрете и выставил бы метод, называемый чем-то вроде WaitForCompletion, в классе Worker, который его вызывает).

Альтернативные методы:

  1. Иметь WaitHandle, вероятно, ManualResetEvent в классе Worker, который равен Set, когда он завершает всю свою работу, и вызывать WaitOne для него.

  2. Иметь поле volatile bool complete в классе Worker и цикл, ожидая, пока он будет установлен на true, используя Thread.Sleep в теле цикла (это, вероятно, не очень хорошее решение, но это возможно).

Возможно, есть и другие варианты, но это общие.

2 голосов
/ 09 января 2009

Использование членов класса WaitHandle (WaitOne, WaitAny или WaitAll)

См. Подробности здесь, в MSDN

2 голосов
/ 09 января 2009

Вы пытались изменить порядок выписок?

static void Main(string[] args)
{
    Worker worker = new Worker();
    worker.WorkCompleted += PostProcess;
    worker.DoWork();
}

WorkCompleted является обработчиком событий и должен быть настроен заранее. Это не вызывается работником назначения. WorkCompleted + = PostProcess;

0 голосов
/ 25 апреля 2009

я думаю Application.Run после инициализации вашей темы. и по завершении вызова Application.Exit

0 голосов
/ 09 января 2009

Звучит как хороший кандидат на использование асинхронного шаблона Begin / End на вашем рабочем месте. Таким образом, вместо простого DoWork() метода, который начинает выполнять работу асинхронно, и события, которое запускается, когда работа завершена, Worker будет включать синхронный метод Work(), который возвращает результат (ы) работы, и BeginWork() и EndWork() пара, которая может использоваться для асинхронного использования.

См. http://msdn.microsoft.com/en-us/library/seta58yd(VS.71).aspx для получения дополнительной информации об этом. Может подойдет для вашей ситуации?

0 голосов
/ 09 января 2009

Для этого вы можете использовать класс BackgroundWorker из .net framework.

Это именно то, что вы хотите сделать. Кроме того, он справляется с вызовом самого себя, поэтому вам не будет больно.

static void Main(string[] args)
{
    BackgroundWorker worker = new BackgroundWorker();

    worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.WorkerReportsProgress = true;
    worker.WorkerSupportsCancellation = false;
    worker.DoWork += new DoWorkEventHandler(MyThreadMethod);
    worker.RunWorkerAsync();
    Console.Read();
}

static void MyThreadMethod(object sender, DoWorkEventArgs e)
{
    Console.WriteLine("Worker starts working.");
    for (int i = 1; i <= 100; i++)
    {
        ((BackgroundWorker)sender).ReportProgress(i);
    }
    Console.WriteLine("Worker works fine.");
}

static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Console.WriteLine("Worker has finished.");
}

static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    Console.WriteLine("Worker reports progress {0}", e.ProgressPercentage);
}
0 голосов
/ 09 января 2009

Предполагая, что у вас нет доступа к классу Worker, просто добавьте флаг, который указывает, когда PostProcessing завершился, и переведите его в спящий режим, пока не будет установлен флаг:

static bool isProcessed = false;
static void Main(string[] args)
{
    Worker worker = new Worker();
    worker.WorkCompleted += PostProcess;
    worker.DoWork();
    while(!isProcessed)
    {
      System.Threading.Thread.Sleep(-1);
    }
}

static void PostProcess(object sender, EventArgs e) 
{ 
   // Cannot see this happening 
   isProcessed=true;
}

Это должно сработать, но я не могу гарантировать его работоспособность без дополнительной информации о ваших настройках.

0 голосов
/ 09 января 2009

Класс Worker должен иметь метод, позволяющий клиенту ожидать завершения потока. Этот метод вызовет соответствующую перегрузку Thread.Join() для реализации ожидания. Если это не так (и у вас нет возможности изменить класс Worker), у него может быть какой-то метод, чтобы добраться до внутреннего объекта Thread, и вы можете выполнить Join () для этого объекта.

Если у него нет ни одного из них, вам нужно посмотреть (и / или опубликовать здесь) более подробную информацию об интерфейсе класса Worker, чтобы увидеть, есть ли у него подходящий метод для ожидания завершения. Если у него его нет, вам понадобится ваш собственный объект EventWaitHandle, о котором обработчик события PostProcess() может сигнализировать при его вызове.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...