2013-10-09 4 views
0

장기 실행 작업은 트랜잭션처럼 작동합니다. 하나의 성공이 다른 작업의 성공에 달려있는 많은 작업이 포함됩니다.작업 실행 일시 중지

class MyTransaction 
{ 
    public void Execute() 
    { 
     StopServices(); 
     BackupFiles(); 
     OverwriteFiles(); 
     BackupDatabases(); 
     RunChangeScripts(); 
     ... and few others   
    } 

    public void RollBack() { } 
} 

class MyTransactionManager 
{ 
    public RunTransactions() 
    { 
     Task.Factory.StartNew(() => { 
      new MyTransaction().Execute(); 
     }); 
    } 
} 

이것은 시스템의 여러 구성 요소가 다른 작업을 수행하는 실제 응용 프로그램의 의사 코드에 불과합니다. 진행 상황 표시 줄을 사용하여 진행 상황을 표시하는 GUI (WinForms)가 있으며 상황에 관계없이 응답 성을 유지해야하는 몇 가지 사항이 있습니다. 트랜잭션은 모두 실제로 오래 실행되므로 작업을 시작할 때 지정할 필요가 없습니다 (TaskCreationOptions 사용), 항상 새로운 스레드에서 실행됩니다. 트랜잭션의 진행은 이벤트를 사용하여 GUI로 다시보고됩니다.

이제 트랜잭션 실행 중에 실패하면 즉시 현재 롤백하지 않는 요청이 있습니다. GUI에서 메시지 상자를 팝업하여 오류를 롤백하거나 수정할지 여부를 결정할 수있는 옵션을 제공하고 마지막 성공한 지점부터 계속 진행하려고합니다.

그래서 어떻게 든 차단을 구현해야합니다. 나는 다른 이벤트를 일으켜서 메시지 상자를 팝업으로 표시하고 "이봐, 고쳐서 다음에 ok"라고 말할 수 있다고 생각했다. 그리고 그 OK 클릭 이벤트를 내 트랜잭션에 요청을 직접 위임 할 수있는 외부 관리자 (공용 API)에 바인딩합니다. 그리고 블로킹은 bool 속성을 확인하는 while 루프를 실행합니다.

이제 수동 차단이 더 좋을 것이라고 생각하지만 실제로 어떻게해야하는지 잘 모릅니다. 제게 조언 해 주시겠습니까?

편집 :이 오류는 수정하는 데 여러 시간이 걸릴 수 있으므로 Thread.Sleep을 사용하고 싶지는 않습니다. 실수와 그것을 고치고있는 사람에 달려 있습니다.

+0

'event'아이디어의 문제점을 이해하지 못합니까? –

+0

'event' 아이디어에는 아무런 문제가 없습니다. while 루프에서 while 루프를 기다리는 중 문제가 있습니다. 수동 대기를 사용하고 싶습니다. –

+0

내 대답은 어떻게됩니까? –

답변

1

처럼 뭔가를 시도 할 수 있습니다 그리고 적극적 일부를 검사하는 동안 루프를 실행 단지 것 차단할 수 있습니다 bool 속성.

블로킹이 아니며 바쁜 대기라고하며 피해야하는 항목입니다.

AskUser(); // doesn't block 
shouldRollbackEvent.WaitOne(); 
if (shouldRollback) … 

그리고 당신의 UI 스레드에서

가 :

shouldRollback = …; 
shouldRollbackEvent.Set(); 

(이것은 두 부분을 가정하면 두 개의 스레드 사이에이 같은 동기화를 갖고 싶어

는 한 가지 방법은 ManualResetEvent 사용하는 것입니다 코드는 동일한 객체 내에서 실행됩니다.)

+0

저를 고치고 좋은 해결책을 제공해 주셔서 감사합니다. –

1

는이

private static Task<bool> WaitTillUserInput() 
{ 
    TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); 
    uiSynchronizationContext.Post(x => 
    { 
     if (MessageBox.Show("Do you want to rollback...?", "Please confirm", MessageBoxButtons.YesNo) == DialogResult.Yes) 
     { 
      tcs.SetResult(true); 
     } 
     else 
     { 
      tcs.SetResult(false); 
     } 
    }, null); 
    return tcs.Task; 
} 

C# 5.0

public async void Execute() 
{ 
    ...Do something 
    //Encountered an error 
    var doRollBack = await WaitTillUserInput(); 
    if(doRollBack) 
    { 
     //rollback here 
    } 
} 

C# 4.0

public void Execute() 
{ 
    ...Do something 
    //Encountered an error 
    var doRollBackTask = WaitTillUserInput(); 
    doRollBackTask.ContinueWith(antecedent => 
    { 
     if (antecedent.Result) 
     { 
      //rollback here 
     } 
    }); 
} 
+0

아, .NET 4.0을 사용 중이라고 지정하지 않았으므로 5.0에서 async/await 기능을 사용할 수 없습니다.적절한 태그를 추가했습니다. 죄송합니다. –

+0

또한 내 내부 코드에서 MessageBox를 호출하지 않아도됩니다. 이 라이브러리는 모든 GUI 프레임 워크와 밀접하게 결합되어서는 안됩니다. –

+0

C# 4.0 용으로 업데이트되었습니다. 시작으로 이것을 받아 들여 UI에서 비즈니스 로직을 분리 할 수있는 방법을 찾을 수 있습니다 :) –

0
EventWaitHandle _wait; 

    private async void buttonStart_Click(object sender, EventArgs e) { 
     _wait = new EventWaitHandle(true, EventResetMode.ManualReset); 
     await Task.Run(() => GoInc()); 
    } 

    private void buttonPause_Click(object sender, EventArgs e) { 
     _wait.Reset(); 
    } 

    private void buttonResume_Click(object sender, EventArgs e) { 
     _wait.Set(); 
    } 

    EventWaitHandle _wait; 

    private void GoInc() { 
     for (int i = 0; i < 10000; i++) { 
      _wait.WaitOne(); 
      Thread.Sleep(100); 
     } 
    } 
관련 문제