2017-04-25 2 views
0

백그라운드에서 처리중인 WPF 응용 프로그램을 작성했습니다. 응용 프로그램이 닫히면 프로세스가 끝나기 전에 처리가 끝날 때까지 기다리고 싶습니다. 이 코드는 폼을 닫아 응용 프로그램을 닫을 때 완벽하게 실행됩니다. 그러나 응용 프로그램을 열린 상태로 유지하여 Windows 세션에서 로그 오프하거나 시스템을 재부팅하면 응용 프로그램이 SemaphoreSlim.Wait()에서 종료 된 것처럼 보입니다. 이상한 것은 이벤트 로그에 기록 된 오류가 없다는 것입니다. 시도 잡기로 오류 캡처를 시도했지만 오류가 여전히 잡히지 않습니다.Windows 로그 오프 전에 스레드가 완료 될 때까지 기다릴 수있는 방법

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 

내가 응용 프로그램을 닫기 전에 완료 스레드에서 코드를 기다릴 수있는 방법이있는 다음 로그에

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

이 결과 : 여기

내 코드? 나는 다양한 (How to wait for thread to finish with .NET?) 스레드 대기 대안을 시도했지만 모두 동일한 동작을 나타내는 것처럼 보입니다.

나는 그물 4.6.2를 사용하고 난

+0

스레드의 기능은 무엇입니까? 파일에 메시지를 쓰는 데 사용되는 경우, 로깅 라이브러리 또는 텍스트를 파일에 추가하는'ActionBlock '으로 완전히 바꿀 수 있습니다. 응용 프로그램을 닫거나'SessionEnding' 이벤트가 발생하면'ActionBlock.Complete()'메소드를 사용할 수 있습니다. 결과는 훨씬 더 깨끗합니다. –

+0

ActionBlock을 사용하여 코드를 다시 작성했습니다. 문제는 응용 프로그램이 ActionBlock.Completion.Wait()에서 종료되지 않는 것과 동일하게 유지됩니다. 우리가 Windows에서 로그 오프 할 때 (폼을 닫으면 올바르게 대기하지만 Windows가 종료되지 않습니다). – DesDesDes

+0

*'SessionEnding'에서'Complete()'를 호출 했습니까? 블록이 작동하지 못하게하는 세마포어 또는 다른 것을 제거 했습니까? '.Wait()'을 사용할 필요가 없으므로 이벤트 처리기의 서명을 async void로 변경하고'await block.Completion;','block.Complete(); 블록을 기다리고 있습니다. 완료. '. –

답변

1

문제는 당신이 처음 base.close 호출되고 Windows 7 및 Windows 10

TIA에 문제

바트 브리스 재현 이벤트 닫음 양식 닫기를 취소해야합니다 스레드 작업이 완료되면 this.close를 호출하지만 이번에는 매개 변수 exit를 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

@DesDesDesce는 세마포어 자체로 신호를받지 않습니다. * 당신의 코드는'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")); 
    } 
} 

도와 주셔서 감사합니다 모두들 : 여기

는 코드입니다.

관련 문제