【发布时间】:2017-04-25 12:29:07
【问题描述】:
我编写了一个 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,
巴特·弗里斯
【问题讨论】:
-
你的线程是做什么的?如果它用于将消息写入文件,则可以将其完全替换为日志库或将文本附加到文件的
ActionBlock<string>。当您关闭应用程序或触发SessionEnding事件时,您可以使用ActionBlock.Complete()方法。结果会干净很多 -
我已经使用 ActionBlock 重写了代码。当我们从 Windows 注销时,问题仍然存在,因为应用程序不会在 ActionBlock.Completion.Wait() 上终止(关闭表单确实等待正确,但 Windows 关闭没有)。
-
是否你打电话给
Complete()SessionEnding?您是否删除了信号量或其他任何会阻止该块工作的东西?不需要使用.Wait(),可以将事件处理程序的签名改为async void并写成await block.Completion;,例如block.Complete(); await block.Completion;。 -
@PanagiotisKanavos 尝试了所有方法,但仍然无法正常工作。与上面的代码中存在相同的问题。当 Windows 注销过程中邮件线程似乎被锁定时,即使等待仅 1 秒,它也会终止应用程序。
标签: c# wpf multithreading logoff