2013-10-09 3 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(); 
     }); 
    } 
} 

Это просто псевдо-код реального приложения, где различные операции обеспечиваются различными компонентами системы. Существует базовый графический интерфейс (WinForms), который отображает прогресс, используя индикатор прогресса и несколько других вещей, которые должны оставаться отзывчивыми независимо от того, что происходит. Транзакции все очень долго работают, поэтому нет необходимости указывать его при запуске задач (используя TaskCreationOptions), он всегда запускается в новом потоке. Прогресс от транзакций сообщается в графический интерфейс с использованием событий.

Теперь есть запрос, что если что-то во время выполнения транзакции не удастся, он не будет немедленно откатываться назад, как это происходит в настоящее время. Они хотят всплывать окно сообщения в графическом интерфейсе, предоставляя пользователю возможность решить, откатываться или исправлять ошибку и продолжать работу с последней успешной точки.

Так что мне нужно как-то реализовать блокировку. Я думал, что могу просто поднять еще одно событие, вскрыть окно сообщения и сказать «Эй, исправить, а затем нажать« ОК ». И свяжите это событие ОК с моим внешним менеджером (public API), который может делегировать запросы непосредственно моим транзакциям. И блокировка просто активно запускает цикл while, проверяющий свойство bool.

Теперь я думаю, что пассивная блокировка будет лучше, но я действительно не знаю, как это сделать. Не могли бы вы посоветовать мне?

EDIT: И я действительно не хочу использовать Thread.Sleep, потому что эти ошибки могут занять некоторое время, чтобы исправить. Зависит от ошибки и человека, который ее исправляет.

+0

Я не понимаю, что случилось с идеей 'event'? –

+0

В идее 'event' нет ничего плохого. Существует проблема с тем, что activelly ожидает цикл while. Я хотел бы использовать пассивное ожидание. –

+0

Как насчет моего ответа ниже? –

ответ

1

И блокирование просто активно запускать цикл при проверке некоторых свойство bool.

Это не блокировка, это называется ожидание, и это то, что вам следует избегать.

Если вы хотите иметь синхронизацию, как это между двумя потоками, один из способов заключается в использовании 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, и поэтому я не могу использовать функции async/await от 5.0.Я добавил соответствующий тег. Сожалею. –

+0

Кроме того, я не хочу вызывать MessageBox из моего внутреннего кода. Эта библиотека не должна быть тесно связана с любой графической оболочкой. –

+0

Обновлено для C# 4.0. Вы можете взять это как начало и найти свой способ отделить бизнес-логику от пользовательского интерфейса: –

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