2017-04-25 43 views
0

我已經編寫了一個WPF應用程序,它在後臺執行一些處理。當應用程序關閉時,我想等到處理完成後才能停止進程。當我通過關閉表單關閉應用程序時,此代碼完美運行。但是,當我離開應用程序打開結束註銷我的Windows會話或重新啓動機器時,應用程序似乎終止於SemaphoreSlim.Wait()。奇怪的是事件日誌中沒有記錄錯誤。我嘗試用try catch捕獲錯誤,但錯誤仍未被捕獲。如何等待一個線程完成Windows註銷之前

這裏是我的代碼:

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和我轉載

+0

你的線程是做什麼的?如果它用於將消息寫入文件,則可以使用日誌庫或將文本附加到文件的'ActionBlock '完全替換它。當關閉應用程序或觸發'SessionEnding'事件時,可以使用'ActionBlock.Complete()'方法。結果會更清晰 –

+0

我用ActionBlock重寫了代碼。當我們從Windows註銷(關閉表單確實等待,但Windows關機不)時,問題仍然與ActionBlock.Completion.Wait()上未終止的應用程序相同。 – DesDesDes

+0

*您在'SessionEnding'上調用了'Complete()'嗎?你是否刪除了信號量或其他會阻止該塊運行的東西? 您不需要使用'.Wait()',您可以將事件處理程序的簽名更改爲'async void'並寫入'await block.Completion;',例如'block.Complete();等待block.Completion;'。 –

回答

1

問題是你先打電話base.close在Windows 7和Windows 10

TIA問題,

巴特弗里斯事件關閉您應該取消形式 結束當線程的任務完成了,你calll this.close但這個時候你設置的參數出口爲true(定義參數)

+0

這個問題並不是由base.close引起的,因爲這樣在通過關閉表單關閉應用程序時它可以重現,並且仍然可以工作。當應用程序由註銷關閉時,CancelEventArgs.Cancel被忽略。這是在這裏記錄:https://msdn.microsoft.com/en-us/library/system.windows.window.closing(v=vs.110).aspx所以,即使這是問題是不能解決的設置取消。 – DesDesDes

3

有一個Application.SessionEnding事件OC當用戶通過註銷或關閉操作系統來結束Windows會話時會發生。你可以嘗試處理這一個。

您的應用程序無法真正控制操作系統的功能。在您的代碼完成之前,用戶可能仍會殺死您的應用程序,並且您對此恐怕沒有太多可以做的事情。

+0

我把代碼從OnClosing移動到Application.SessionEnding,但問題依然如故。如果仍然停止處理_locker.Wait(); – DesDesDes

+0

@DesDesDes信號將不會自行發出信號。 *您的代碼*必須在'SessionEnding'中發信號。你不必在事件內部移動你的代碼hanlder –

+0

@PanagiotisKanavos只需爲自己嘗試一下代碼,你就會發現,Windows註銷注意到郵件應用程序線程正在等待一個信號量,只是殺死了應用程序而沒有寫任何東西事件日誌。 – DesDesDes

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")); 
    } 
} 

感謝大家的幫助。

相關問題