2013-10-09 94 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事件點擊事件綁定到我的外部管理器(公共API),該管理器可以將請求直接委託給我的事務。而阻塞會主動運行一個while循環檢查一些布爾屬性。

現在我在想,被動阻塞會更好,但我真的不知道該怎麼做。你能告訴我嗎?

編輯:我真的不想使用Thread.Sleep,因爲這些錯誤可能需要不同的時間來解決。取決於錯誤和修復它的人。

+0

我不明白'event'的想法有什麼問題嗎? –

+0

「事件」的想法沒有錯。該activelly等待while循環有一個問題。我想用被動等待。 –

+0

我的答案如何? –

回答

1

和阻斷只想積極地運行一個while循環檢查一些布爾財產。

這不是阻塞,它被稱爲繁忙的等待,這是你應該避免的。

如果你想有兩個線程之間這樣的同步,一個方法是使用ManualResetEvent

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

並在您的UI線程:

shouldRollback = …; 
shouldRollbackEvent.Set(); 

(這是假設的兩個部分代碼在同一個對象內執行。)

+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中的異步/等待功能。我添加了相應的標籤。抱歉。 –

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