2013-07-05 11 views
5

Mam zadanie jak poniżej.Task.wait i kontynuacja

var task = Task<string>.Factory.StartNew(() => longrunningmethod() 
    .ContinueWith(a => 
      longrunningmethodcompleted((Task<string>)a, 
        TaskScheduler.FromCurrentSynchronizationContext()))); 

task.Wait(); 

Moje zadanie wywoła metodę longrunning, a po jej zakończeniu wywoła metodę zakończoną. Wewnątrz mojego longrunningmethod opóźniam o Thread.Sleep(30000). Kiedy używam systemu Task.wait zawiesza się i nie wywołuje metody longrunningmethodcompleted. Jeśli nie używam Task.wait, wszystko przepływa dobrze.

+0

Brzmi dla mnie jak zakleszczenie, czy robisz to w środowisku z pojedynczym gwintem? Widziałem to już wcześniej w rozwoju Windows Phone. ([related] (http://stackoverflow.com/questions/8277291/continuation-tasks-hanging-when-using-limitedconcurrencyleveltaskscheduler)) –

Odpowiedz

12

Podejrzewam, że twój kontekst jest kontekstem interfejsu użytkownika.

W takim przypadku przyczyną jest zakleszczenie, ponieważ mówi się, że longrunningmethodcompleted należy wykonać na bieżącym .

Następnie blokujesz ten kontekst dzwoniąc pod numer Wait. Kontynuacja nigdy się nie zakończy, ponieważ musi zostać wykonana w wątku zablokowanym w Wait.

Aby to naprawić, nie można używać Wait w kontynuacji działającej w tym kontekście. Jestem zakładając, że longrunningmethodcompletedmusi bieg na wątku UI, więc rozwiązaniem jest zastąpienie wywołanie Wait z wezwaniem do ContinueWith:

var ui = TaskScheduler.FromCurrentSynchronizationContext(); 
var task = Task<string>.Factory.StartNew(() => longrunningmethod() 
    .ContinueWith(a => 
     longrunningmethodcompleted((Task<string>)a, 
     ui); 
task.ContinueWith(..., ui); 

Albo, można uaktualnić do VS2012 i używać async/await , który pozwala pisać znacznie czystsze kodu:

var task = Task.Run(() => longrunningmethod()); 
await task; 
longrunningmethodcompleted(task); 
+0

Dziękuję wszystkim.Stephen Tak to działa. Używam vs2010 niestety nie mogę uaktualnić teraz do vs2012.IS tam sposób, w jaki mogę uczynić wątek UI, aby poczekać do zadania i kontynuować. – user2107843

+0

Jedynymi opcjami są: kontynuacja * bez * terminarza zadań lub pozostawienie pozostałej części pracy jako kontynuacji. Tak, to bardzo szybko staje się nieporządne w przypadku dowolnego asynchronicznego scenariusza w świecie rzeczywistym. I właśnie dlatego wynaleziono 'async'. –

-1

Thread.Sleep (nnn) jest blokowany. Użyj Task.Delay (nnn) i czekają:

await Task.Delay(30000); 

Edited by dodać: Wystarczy zaznaczyć znacznik mówi C# 4. Wymaga C# 5 oraz nowy asynchroniczny czekają na wsparcie. Poważnie, jeśli robisz asynchroniczne i zadania, musisz uaktualnić.

+0

C# 4.0 nie czeka na – konkked

0

No to trudno powiedzieć co jest nie tak z kodem, nie widząc tego, co rzeczywiste działania asynch to wszystko co wiem, to zgodnie z MSDN waits for the task to be completed. Czy jest możliwe, że ponieważ próbujesz użyć bieżącej synchronizacji, twoje akcje blokują?

Powodem Pytam dlatego, że

  1. Uruchom zadanie
  2. Poczekaj na zadanie do wykonania (co jest kontynuowanie zadania)
  3. Zadanie próbuje kontynuować bieżącego SynchronizationContext
  4. Zadanie próbuje nabyć główny wątek
  5. zadań zaplanowanych do podjęcia nitkę po zakończeniu Wait
  6. Ale Czekaj czeka na bieżące zadanie do wykonania (deadlock)



Chodzi mi o to, że powodem, dla którego twój program działa z Thread.Sleep(seconds), jest fakt, że po upłynięciu limitu czasu wątek będzie kontynuowany.

+0

Charles dziękuje Tak, rozumiem teraz, że zakleszczenie się stało Powodem, dla którego potrzebuję Task.wait po tym, jak kontynuować, jest sprawienie, by wątek interfejsu użytkownika czekał. Jest tam sposób, w jaki mogę użyć głównego wątku, poczekać do zadania i kontynuować. – user2107843

Powiązane problemy