如何在Windows注销之前等待线程完成

时间:2017-04-25 12:29:08

标签: c# wpf multithreading logoff

我编写了一个WPF应用程序,它在后台进行一些处理。当应用程序关闭时,我想等到处理完成后才停止进程。当我通过关闭表单关闭应用程序时,此代码运行完美。但是当我离开应用程序打开结束注销我的Windows会话或重启机器时,应用程序似乎终止在SemaphoreSlim.Wait()上。奇怪的是事件日志中没有记录错误。我尝试使用try catch捕获错误,但错误仍然没有被捕获。

这是我的代码:

  public partial class NotifyWindow : Window
  {
    StreamWriter _stream;

    public NotifyWindow()
    {
      InitializeComponent();

      _stream = File.AppendText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log.txt"));

      WriteLine("startup");
    }

    private void WriteLine(string line)
    {
      var text = string.Format("{0}    {1}", DateTime.Now, line);

      lock (_stream)
      {
        _stream.WriteLine(text);
        _stream.Flush();
      }
    }

    SemaphoreSlim _locker = new SemaphoreSlim(0);

    private void CloseMe()
    {
      WriteLine(string.Format("CloseMe started"));
      Thread.Sleep(1000);

      WriteLine(string.Format("release lock"));
      _locker.Release();

      WriteLine(string.Format("CloseMe finished"));
    }

    protected override void OnClosing(CancelEventArgs e)
    {
      WriteLine(string.Format("OnClosing started"));

      base.OnClosing(e);

      var t = new Thread(CloseMe);
      t.Start();

      WriteLine("Waiting on lock.");
      _locker.Wait();
      WriteLine("Waiting on lock finished.");

      WriteLine(string.Format("OnClosing finished"));
    }
  }

这导致以下日志

When application is closed by closing the window
24-4-2017 13:57:29    startup
24-4-2017 13:57:30    OnClosing started
24-4-2017 13:57:30    Waiting on lock.
24-4-2017 13:57:30    CloseMe started
24-4-2017 13:57:31    release lock
24-4-2017 13:57:31    CloseMe finished
24-4-2017 13:57:31    Waiting on lock finished.
24-4-2017 13:57:31    OnClosing finished

When application is closed by windows logoff
24-4-2017 13:57:43    startup
24-4-2017 13:57:47    OnClosing started
24-4-2017 13:57:47    Waiting on lock.
24-4-2017 13:57:47    CloseMe started

有没有办法可以在关闭应用程序之前等待线程上的代码完成?我尝试了各种(How to wait for thread to finish with .NET?)线程等待替代,但所有似乎都表现出相同的行为。

我正在使用.net 4.6.2,我在Windows 7和Windows 10上重现了这个问题。

TIA,

Bart Vries

3 个答案:

答案 0 :(得分:3)

当用户通过注销或关闭操作系统结束Windows会话时,会发生Application.SessionEnding事件。你可以尝试处理这个。

您的应用程序无法真正控制操作系统的功能。在您的代码完成之前,用户仍然可能会终止您的应用程序,而且恐怕您无法做到这一点。

答案 1 :(得分:1)

问题是你在事件关闭时首先调用base.close你应该取消表单的关闭 完成线程作业后,你会调用this.close,但这次你将参数exit设置为true(定义参数)

答案 2 :(得分:0)

谢谢大家的反馈。根据您的反馈,我发现了一种不使用任何操作系统锁定机制的解决方法。这似乎有效。

以下是代码:

public partial class NotifyWindow : Window
{
  StreamWriter _stream;
  volatile int _running = 0;

  public NotifyWindow()
  {
    InitializeComponent();

    _stream = File.AppendText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log.txt"));

    WriteLine("startup");
  }

  private void WriteLine(string line)
  {
    var text = string.Format("{0}    {1}", DateTime.Now, line);

    lock (_stream)
    {
      _stream.WriteLine(text);
      _stream.Flush();
    }
  }

  private void CloseMe()
  {
    WriteLine(string.Format("CloseMe started"));
    Thread.Sleep(1000);

    WriteLine(string.Format("release lock"));
    _running = 1;

    WriteLine(string.Format("CloseMe finished"));
  }

  protected override void OnClosing(CancelEventArgs e)
  {
    WriteLine(string.Format("OnClosing started"));

    base.OnClosing(e);

    var t = new Thread(CloseMe);
    t.Start();

    WriteLine("Waiting on lock.");

    while(_running == 0)
    {
      Thread.Sleep(50);
      WriteLine("Waiting for 50ms.");
    }

    WriteLine("Waiting on lock finished.");

    WriteLine(string.Format("OnClosing finished"));
  }
}

谢谢大家的帮助。