2011-02-13 3 views
3

Мне нужно запустить список методов синхронно, с возможностью остановить список выполнения. Легко остановить цикл перед выполнением с помощью события сброса (см. Первую строку в Execute).Как написать прерывистый синхронный метод?

Как подождать ответа от action.Execute() и action.Execute() в то же время?

private ManualResetEvent _abortingToken = new ManualResetEvent(false); 
private List<IAction> _actions; 

public void Abort() 
{ 
    _abortingToken.Set(); 
} 

public void Execute() 
{ 
    foreach (var action in _actions) 
    { 
     if (_abortingToken.WaitOne(0)) 
      break; // Execution aborted. 

     action.Execute(); // Somehow, I need to call this without blocking 

     while (/*Execute not finished*/) 
     { 
      if (_abortingToken.WaitOne(1)) 
       action.Abort(); 
     } 
    } 
} 

Я думаю, что было бы легко преформировать, используя Задачи, но, к сожалению, я использую .net 3.5.


Edit: решение вдохновлен SLaks answer:

public void Execute() 
{ 
    Action execute = null; 
    IAsyncResult result = null; 

    foreach (var action in _actions) 
    { 
     execute = new Action(scriptCommand.Execute); 

     if (_abortingToken.WaitOne(0)) 
      break; // Execution aborted. 

     result = execute.BeginInvoke(null, null); 

     while (!result.IsCompleted) 
     { 
      if (_abortingToken.WaitOne(10)) 
      { 
       action.Abort(); 
       break; 
      } 
     } 

     execute.EndInvoke(result); 
    } 
} 

ответ

2

Это противоположность синхронности.
Вам нужно запустить метод в фоновом потоке.

Например, вы можете вызвать метод, используя Delegate.BeginInvoke, а затем проверить IAsyncResult.IsCompleted. (и обязательно позвоните по телефону EndInvoke)

+0

спасибо. Использование 'BeginInvoke' создает очень элегантный код без большого количества накладных расходов. Но я должен назвать «EndInvoke»? Не единственная цель «EndInvoke» - вернуть возвращаемое значение или исключения? Что делать, если мне не нужен результат (т. Е. После прерывания)? – HuBeZa

+0

@HuBeZa: Если вы не вызываете «EndInvoke», вы будете утечка памяти. – SLaks

0

Вы можете запустить Execute в другой теме, а затем попытаться присоединиться к таймауту.

public void Execute() 
{ 
    foreach (var action in _actions) 
    { 
     if (_abortingToken.WaitOne(0)) 
      break; // Execution aborted. 

     var workThread = new Thread(action.Execute); 
     workThread.Start(); 

     while (!workThread.Join(100)) /Milliseconds, there is also a timespan overload 
     { 
      if (_abortingToken.WaitOne(1)) 
       action.Abort(); 
     } 
    } 
} 

См. http://msdn.microsoft.com/en-us/library/system.threading.thread_methods.aspx.

+1

ThreadPool (используется 'BeginInvoke') дешевле. – SLaks

Смежные вопросы