暂停任务执行

时间:2013-10-09 13:48:38

标签: c# events c#-4.0 task-parallel-library blocking

我有一个长期运行的任务,其行为类似于交易 - 它涉及许多操作,其中一个操作的成功取决于另一个操作的成功。

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循环检查一些bool属性。

现在我认为被动阻挡会更好,但我真的不知道该怎么做。你能告诉我吗?

编辑:我真的不想使用Thread.Sleep,因为这些错误可能需要不同的时间来修复。取决于错误和正在修理错误的人。

3 个答案:

答案 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
        }
    });
}

答案 1 :(得分:1)

  

阻塞只会主动运行while循环检查一些bool属性。

没有阻止,它被称为忙碌等待,这是你应该避免的事情。

如果你想在两个线程之间进行这样的同步,一种方法是使用ManualResetEvent

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

在你的UI线程上:

shouldRollback = …;
shouldRollbackEvent.Set();

(这假设代码的两个部分都在同一个对象中执行。)

答案 2 :(得分: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);
        }
    }