Проблема многопоточности WinForms - PullRequest
4 голосов
/ 28 июля 2011

У меня есть поток, который выполняет некоторую работу в фоновом режиме и передает обновления в форму, используя методы Invoke, BeginInvoke. Тема создается после того, как форма отображается, поэтому никаких проблем нет.

Вопрос в том, как правильно завершить работу. У моего рабочего потока есть возможность получить запрос на выход, и вскоре после этого он выйдет (миллисекунды).

Однако, если форма закрылась первой, материал Invoke ломается. Я попытался добавить Thread.Join к событию закрытия форм, но, конечно, это вызывает тупик, даже для BeginInvoke, так как поток Thread.Join блокирует BeginInvoke в этом потоке ...

Как правильно закрыть форму и аккуратно закрыть ее рабочий поток?

EDIT:

основной текущий код:

volatile bool abort;
void WorkerThread()
{
    while(!abort)DoStuffIncludingInvokesOnThisForm();
}
void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
    abort = true;
    workerThread.Join();//will deadlock with DoStuffIncludingInvokesOnThisForm
    //if get here before workerThread has exited, invokes will fail if workerthread is still in DoStuffIncludingInvokesOnThisForm
}

Ответы [ 2 ]

1 голос
/ 28 июля 2011

Из обработчика событий Form.Closing установите для свойства Cancel значение true, чтобы временно отложить закрытие формы до завершения рабочего потока.После завершения рабочего потока вы можете снова ввести команду Close в форме.

public class MyForm : Form
{
  private volatile bool abort = false;
  private bool IsCloseRequested = false;
  private bool IsWorkerThreadComplete = false;

  private void MyForm_Closing(object sender, FormClosingEventArgs args)
  {
    if (!IsWorkerThreadComplete)
    {
      args.Cancel = true;
      IsCloseRequested = true;
      abort = true;
    }
  }

  void WorkerThread()
  {
    try
    {    
      while (!abort) DoStuffIncludingInvokesOnThisForm();
    }
    finally
    {
      OnWorkerThreadComplete();
    }
  }

  private void OnWorkerThreadComplete()
  {
    if (InvokeRequired) 
    {
      Invoke(((MethodInvoker)() => OnWorkerThreadComplete), null);
    }
    else
    {
      IsWorkerThreadComplete = true;
      if (IsCloseRequested) Close();
    }
  }
}
1 голос
/ 28 июля 2011

Добавьте обработчик в FormClosing и попросите ваш поток завершить работу ...

...