2017-04-25 26 views
0

バックグラウンドで何らかの処理を行う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を使用していますが、私は問題はあなたが最初base.closeを呼んでWindows 7およびWindows 10

TIA、

バート・フリース

+0

あなたのスレッドは何をしていますか?メッセージをファイルに書き込むために使用されている場合は、ロギングライブラリまたはテキストをファイルに追加する 'ActionBlock 'のいずれかで完全に置き換えることができます。アプリケーションを閉じるときや 'SessionEnding'イベントが発生したときに' ActionBlock.Complete() 'メソッドを使うことができます。結果はきれいになります –

+0

私はActionBlockを使ってコードを書き直しました。問題は、ウィンドウからログオフするときにアプリケーションがActionBlock.Completion.Wait()で終了しない場合と同じままです(フォームを閉じても正しく待機しますが、Windowsはシャットダウンしません)。 – DesDesDes

+0

* 'SessionEnding'で' Complete() 'を呼び出しましたか?ブロックが動作しないようにするセマフォーなどを削除しましたか? '.Wait()'を使う必要はありません。イベントハンドラのシグネチャを 'async void'に変更し、' await block.Completion; 'と書くことができます。例えば' block.Complete(); block.Completion;を待つ。 –

答えて

1

上の問題を再現イベントクローズフォームのクローズをキャンセルする必要があります スレッドジョブが完了したら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

ocのイベントはApplication.SessionEndingですユーザーがオペレーティングシステムをログオフまたはシャットダウンしてWindowsセッションを終了したときに消えます。あなたはこれを処理しようとする可能性があります。

アプリケーションでは、オペレーティングシステムの動作を実際は制御できません。あなたのコードが完成し、これについて私が恐れていることはあまりありません。

+0

コードをOnClosingからApplication.SessionEndingに移動して揚げましたが、問題は同じです。 _locker.Wait();の処理がまだ停止している場合。 – DesDesDes

+0

@DesDesDesセマフォーはそれ自身でシグナルを受け取らないでしょう。 *あなたのコードは、 'SessionEnding'でそれを伝える必要があります。イベントハンドラー内でコードを移動する必要はありません –

+0

@PanagiotisKanavos自分でコードを試してみると、何らかの形でWindowsログオフに気付くと、メールアプリケーションスレッドはセマフォを待っていて、何も書かずにアプリケーションを終了しますイベントログ – DesDesDes

0

ご協力いただきありがとうございます。あなたのフィードバックに基づいて、OSロック機構を使用しないで回避策を見つけました。これは機能しているようです。ここで

は、コードは次のとおりです。あなたの助けのための

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

おかげであなたのすべてを。

関連する問題