代码之家  ›  专栏  ›  技术社区  ›  Ondrej Janacek

暂停任务执行

  •  0
  • Ondrej Janacek  · 技术社区  · 11 年前

    我有一个长时间运行的任务,它的行为就像一个事务——它涉及许多操作,其中一个操作的成功取决于另一个的成功。

    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),它可以将请求直接委托给我的事务。阻塞只会主动运行一个while循环,检查一些bool属性。

    现在我认为被动拦截会更好,但我真的不知道怎么做。你能给我建议吗?

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

    3 回复  |  直到 11 年前
        1
  •  1
  •   svick    11 年前

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

    这不是阻塞,这被称为忙等待,这是你应该避免的事情。

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

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

    在您的UI线程上:

    shouldRollback = …;
    shouldRollbackEvent.Set();
    

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

        2
  •  1
  •   Sriram Sakthivel    11 年前

    也许你可以试试这样的东西

    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
            }
        });
    }
    
        3
  •  0
  •   HuckFin.7b    8 年前
        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);
            }
        }