2016-09-13 4 views
-1

입력 양식 Stephen Cleary로 문제를 해결할 수있었습니다. 업데이트 3을 참조하십시오.비동기/스레드 타이머로 대기 중

async 한정자가있는 메서드가있는 Windows Forms 응용 프로그램이 있습니다. 메서드가 버튼의 클릭 이벤트 내에서 호출되면 UI 스레드를 차단하지 않습니다. 그러나 타이머 내에서 콜백으로 호출하면 UI가 고정됩니다. 나는 내가 여기서 잘못하고있는 것을 알아낼 수 없었다. 내 코드 아래를 참조하십시오. 이것은 데모 용 샘플 프로젝트입니다.

public Form1() 
{ 
    InitializeComponent();    
} 

private async void formCloseAsync() 
{ 
    shutdown stf = new shutdown(); 
    stf.StartPosition = FormStartPosition.CenterScreen; 
    stf.Show(); 
    var task = Task.Factory.StartNew(processClose); 
    await task; 
} 

private void processClose() 
{ 
    Thread.Sleep(5000); 
    Environment.Exit(1); 
} 

private void simpleButtonAsync_Click(object sender, EventArgs e) 
{ 
    formCloseAsync(); 
}   

private void _simpleButtonTimer_Click(object sender, EventArgs e) 
{ 
    Timer _shutdownTimer = new Timer(delegate 
    { 
     formCloseAsync(); 
    }, null, 5000, Timeout.Infinite); 
} 

업데이트 1 : 모든 당신의 소중한 의견에 대한 감사합니다. 아래의 업데이트 된 코드를 참조하십시오.

public Form1() 
    { 
     InitializeComponent(); 

    } 

    private Timer _shutdownTimer; 
    private void formCloseAsync() 
    { 
     shutdown stf = new shutdown(); 
     stf.StartPosition = FormStartPosition.CenterScreen; 
     stf.Show(); 

     Task.Run(async()=> 
      { 
       await Task.Delay(5000); 
       Environment.Exit(1); 
      } 
     ); 
    } 

    private void simpleButtonAsync_Click(object sender, EventArgs e) 
    { 
     formCloseAsync(); 
    } 

    private void _simpleButtonTimer_Click(object sender, EventArgs e) 
    { 
     _shutdownTimer = new Timer(async delegate 
     { 
      formCloseAsync(); 
     }, null, 0, Timeout.Infinite); 
    } 

그러나 여전히 동일한 문제가 있습니다. 타이머 콜백 내에서 호출되면 shutdown stf가 차단됩니다. 기본 UI는 괜찮습니다. 그 문제는 없습니다. 타이머 콜백에서 생성 된 경우 shutdown (stf) GUI가 반응 형이어야합니다. 종료 GUI에 진행률 표시 줄이 있습니다.

업데이트 3 :

await Task.Delay(5000); 

Thread.Sleep 이후 실제로 블록 현재 스레드와 비동기 메서드 내에서 사용할 수 없습니다 : 여기

최종 코드를 대신

public partial class Form1 : Form 
{ 
    readonly shutdown _stf = new shutdown(); 
    public Form1() 
    { 
     InitializeComponent(); 

    } 

    private Timer _shutdownTimer; 
    private async Task formCloseAsync() 
    { 

     try 
     { 
      BeginInvoke(new MethodInvoker(delegate 
      { 

       _stf.StartPosition = FormStartPosition.CenterScreen; 
       _stf.Show(); 
      })); 
      await Task.Run(async() => 
          { 
           await Task.Delay(5000); 
          }); 

     } 
     catch (Exception ex) 
     { 

      MessageBox.Show(ex.ToString()); 

     } 
     finally 
     { 
      Environment.Exit(1); 
     } 

    } 

    private void simpleButtonAsync_Click(object sender, EventArgs e) 
    { 
     formCloseAsync(); 
    } 

    private void _simpleButtonTimer_Click(object sender, EventArgs e) 
    { 
     _shutdownTimer = new Timer(async delegate 
     { 
      formCloseAsync(); 
     }, null, 0, Timeout.Infinite); 
    } 

    private async void Form1_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     e.Cancel = true; 
     await formCloseAsync(); 
    } 

답변

1

는 그러나, UI를 정지.

백그라운드 스레드에서 UI 요소에 액세스 할 수 없습니다 (나는 stf.Show();이 대화 상자를 표시하고 있다고 생각합니다). 가장 쉬운 해결 방법은 System.Threading.TimerWindows.Forms.Timer으로 대체하는 것입니다.

기타 사항 :

  • 당신은 그것에 대해 StartNew을 사용하지 말아야합니다; 대신 Task.Run을 사용하십시오. 내 블로그 게시물 StartNew is dangerous을 참조하십시오.
  • 이벤트 처리기 이외에는 async void을 사용하면 안됩니다. 내 MSDN 기사 Best Practices in Asynchronous Programming을 참조하십시오.
+0

안녕하세요 @ steephen 귀하의 의견에 너무 감사드립니다. 원래 게시물을 업데이트했습니다. 상기 참조하십시오. 어느 UI가 고정되고 있는지 정확하게 말하지 않았을 수 있습니다. 양식 타이머라고도 불리는 응답이없는 UI를 종료합니다. – IamaC

+0

@IamaC : 같은 대답이 적용됩니다. 백그라운드 스레드에서 UI 코드를 실행하지 마십시오. –

+0

감사합니다. @stephen. 귀하의 의견으로 문제를 해결할 수있었습니다. 업데이트 3을 참조하십시오. – IamaC

5

사용 Task.Delay입니다 .

당신은 여기에 대한 자세한 내용을 확인할 수 있습니다 내가 콜백으로 타이머 내부를 호출 할 때 When to use Task.Delay, when to use Thread.Sleep?

+3

수면이 배경 스레드에서 호출되므로 문제가되지 않습니다. 그는 그것을 바꿔야하지만 그가 가지고 있다고 주장하는 문제는 일으키지 않을 것입니다. – Servy

+0

고마워요. 저를 지적 해 주셔서 감사합니다. – IamaC