Проблема многопоточности WinForms

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

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

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

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

РЕДАКТИРОВАТЬ:

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

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
}

person Will    schedule 27.07.2011    source источник


Ответы (2)


Добавьте обработчик в FormClosing и попросите свой поток выйти красиво...

person Icarus    schedule 27.07.2011
comment
Что ж, у меня уже есть логика, чтобы попросить его выйти, и, как я уже сказал, он завершает работу в течение миллисекунд после того, как его попросят, но как сохранить форму до тех пор, пока она не исчезнет, ​​когда использование Thread.Join вызывает блокировку всех вызовов, поэтому рабочий поток получает застрял в одном. - person Will; 28.07.2011
comment
Уилл, разве вы не можете просто дождаться выхода потока, выполнив какой-то цикл внутри FormClosing, например: while(NastyThread.isAlive)Thread.Sleep(100);? - person Icarus; 28.07.2011
comment
@Icarus: Нет, это было бы так же плохо, как звонить Thread.Join. Он по-прежнему блокирует поток пользовательского интерфейса. - person Brian Gideon; 28.07.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();
    }
  }
}
person Brian Gideon    schedule 27.07.2011