2015-01-11 4 views
1

Как вы можете видеть в моем коде ниже, ProcessThisEmployee вызывается для каждого из сотрудников. В рамках этого метода я вызываю метод Clean для сторонней библиотеки, когда операция отменяется. Предположим, что метод Clean занимает довольно много времени. То, что я хотел бы сделать, - отобразить некоторое сообщение в пользовательском интерфейсе, когда метод Clean для всех запущенных экземпляров метода ProcessThisEmployee завершен. Это означает, что мне нужно дождаться завершения всех методов Clean. На данный момент у меня есть WaitAll для задач, но я не уверен, что он будет ждать завершения всех показов. Есть идеи?Как подождать метод регистрации маркера отмены в PLINQ

class ProcessEmployees 
{ 
    private List<Employee> _Employees; 
    CancellationTokenSource cs = new CancellationTokenSource(); 

    public ProcessEmployees() 
    { 
     _Employees = new List<Employee>() 
     { 
      new Employee() { ID = 1, FirstName = "John", LastName = "Doe" }, 
      new Employee() { ID = 2, FirstName = "Peter", LastName = "Saul" }, 
      new Employee() { ID = 3, FirstName = "Mike", LastName = "Sue" }, 
      new Employee() { ID = 4, FirstName = "Catherina", LastName = "Desoza" }, 
      new Employee() { ID = 5, FirstName = "Paul", LastName = "Smith" } 
     }; 
    } 

    public void StartProcessing() 
    { 
     try 
     { 
      Task[] tasks = this._Employees.AsParallel().WithCancellation(cs.Token).Select(x => this.ProcessThisEmployee(x, cs.Token)).ToArray(); 
      Task.WaitAll(tasks); 
     } 
     catch (AggregateException ae) 
     { 
      // error handling code 
     } 
     // other stuff 
    } 

    private async Task ProcessThisEmployee(Employee x, CancellationToken token) 
    { 
     ThirdPartyLibrary library = new ThirdPartyLibrary(); 
     token.ThrowIfCancellationRequested(); 

     using(token.Register(() => library.Clean()) 
     { 
      await Task.Factory.StartNew(() => library.SomeAPI(x)); 
     } 
    } 
} 
+0

Можете ли вы просто отказаться от работы на заднем плане и сразу же сделать интерфейс, как если бы аннулирование было завершено? Обычно это делается как надежная отмена. – usr

+0

Проблема заключается в том, что эта библиотека выполняет некоторые дорогостоящие операции (например, запускает некоторые внешние процессы), поэтому очень важно как-то убедиться, что очистка только что завершилась, прежде чем я дам подтверждение пользователям о том, что отменяется, и они могут продолжить повторную попытку (или что бы они ни хотели) –

ответ

2

Ну, вы можете легко дождаться всего этого, используя CountdownEvent. Вы можете установить его размер в начале, сигнализировать его после каждого library.Clean() и ждать, пока она достигнет 0, используя Wait():

private CountdownEvent _countdownEvent; 
public void Cancel() 
{ 
    cs.Cancel(); 
    _countdownEvent.Wait(); 
    // Update UI 
} 

public void StartProcessing() 
{ 
    try 
    { 
     _countdownEvent = new CountdownEvent(_Employees.Count); 
     Task[] tasks = this._Employees.AsParallel().WithCancellation(cs.Token).Select(x => this.ProcessThisEmployee(x, cs.Token)).ToArray(); 
     Task.WaitAll(tasks); 
    } 
    catch (AggregateException ae) 
    { 
     // error handling code 
    } 
    // other stuff 
} 

private async Task ProcessThisEmployee(Employee x, CancellationToken token) 
{ 
    ThirdPartyLibrary library = new ThirdPartyLibrary(); 
    token.ThrowIfCancellationRequested(); 

    using(token.Register(() => { library.Clean(); _countdownEvent.Signal(); }) 
    { 
     await Task.Factory.StartNew(() => library.SomeAPI(x)); 
    } 
} 

Однако вы должны понимать, что то, что вы пытаетесь сделать, может быть опасно, так как вы можете 't, когда отменяется. Если некоторые из ваших сотрудников находятся до или после блока использования, и вы отменяете операцию, то library.Clean не будет вызываться, и вы можете дождаться его навсегда.

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

  • Нет связанных вопросов^_^