2014-04-16 13 views
7

Tytuł mówi wszystko. Czy jest coś nie tak z await Task.Run(() => semaphore.WaitOne());? System.Threading.Semaphore nie jest wątły-afiniczny, więc nie sądzę, że byłby to problem. Wiem, że klasa SemaphoreSlim jest dostępna, ale muszę wykonać synchronizację między procesami, a SemaphoreSlim tego nie robi.Czy jest coś złego w oczekiwaniu na Task.Run (() => semaphore.WaitOne())?

Czy mogę/powinienem utworzyć własny niestandardowy typ WaitHandle?

+5

Technicznie nie ma problemu z robieniem tego. To, czy powinieneś to zrobić, zależy od wielu innych szczegółów, które nie są określone w twoim poście. –

+2

Podstawowa operacja jest z natury asynchroniczna, a mimo to wątek puli wątków synchronicznie czeka na działanie asynchroniczne, aby można asynchronicznie wskazać, kiedy skończysz. Jest to generalnie kiepski projekt i należy go w miarę możliwości unikać. To znak, że prawdopodobnie nie powinieneś używać "Semafora" w pierwszej kolejności. – Servy

+0

Wskazuje to na błąd z Twojej strony lub wątpliwy projekt. Podejrzewam, że ten pierwszy - mówisz, że "musisz zrobić synchronizację między procesami", ale to naprawdę nie będzie synchronizować niczego. Jeśli proces wywołujący 'WaitOne' faktycznie musi wiedzieć kiedy sygnalizator jest sygnalizowany, dlaczego nie oczekuje synchronicznie? Jeśli nie potrzebuje wiedzieć, dlaczego w ogóle ma semafor? –

Odpowiedz

4

Jeśli próbujesz utrzymać UI reaguje czekając na semaforze tutaj, to może mieć sens, ale jest pewien haczyk: "Semaphores don't have owners". Jeśli udostępnisz semafor między dwoma procesami, a inny proces zawiesza się bez wywoływania Semaphore.Release(), prawa własności do zasobu udostępnionego zostaną utracone. Pozostały proces może nie być w stanie go odzyskać.

IMO, semantyczne Mutex byłoby bardziej odpowiednie tutaj, ale z Mutex potrzebujesz powinowactwa wątku. Być może, można nabyć mutex, dostęp do zasobów i zwolnić go w tym samym wątku:

await Task.Factory.StartNew(() => 
{ 
    mutex.WaitOne(); 
    try 
    { 
     // use the shared resource 
    } 
    finally 
    { 
     mutex.ReleaseMutex(); 
    } 
}, TaskCreationOptions.LongRunnning); 

Jeśli nie jest to możliwe (na przykład dlatego, że trzeba uzyskać dostęp do zasobu udostępnionego na głównym wątku UI), można użyj dedykowanego wątku dla muteksa. Można to zrobić za pomocą niestandardowego programu do planowania zadań, np. Stephen Toub na StaTaskScheduler z numberOfThreads:1 (gwint pomocnik nie musi być w tym przypadku STA):

using (var scheduler = new StaTaskScheduler(numberOfThreads: 1)) 
{ 
    await Task.Factory.StartNew(
     () => mutex.WaitOne(), 
     CancellationToken.None, 
     TaskCreationOptions.None, 
     scheduler); 
    try 
    { 
     // use the shared resource on the UI thread 
    } 
    finally 
    { 
     Task.Factory.StartNew(
      () => mutex.ReleaseMutex(), 
      CancellationToken.None, 
      TaskCreationOptions.None, 
      scheduler).Wait(); 
    } 
} 

Updated, jeśli jesteś zaniepokojony WinRT (tj .NET for Windows Store Apps) lub Windows Phone, a następnie Task.Factory.StartNew w/TaskCreationOptions.LongRunning nadal tam jest, możesz go używać zamiast new Thread() z StaTaskScheduler lub coś podobnego do mojego ThreadWithSerialSyncContext, gdy potrzebujesz gwintu tła z powinowactwem.

+0

Ładne rozwiązanie, ale nie sądzę, że to działa dla mnie.Nie mogę użyć 'Mutex', ponieważ muszę poczekać na pewne zadania, podczas gdy ja nabyłem semafor, a więc blokady wątku są nieodłączne. Użycie 'Wait()' lub 'RunSynchronously()' również nie jest opcją. Proponowane przez ciebie rozwiązanie "StaTaskScheduler" brzmi dobrze, ale niestety, w najnowszej iteracji API WinRT, klasa "Thread" jest nieistniejąca. Zablokowanie twardego resetu systemu (który i tak wyczyści semafor), jeśli zsynchronizuję kod w próbie/końcu, czy istnieje możliwość opuszczenia semafora? –

+0

@ZaneKaminski, jeśli ostrożnie zbilansujesz 'WaitOne' /' Release' z 'try' /' finally' wszędzie, powinieneś być w porządku z tym podejściem. – Noseratio

+0

@ZaneKaminski, również sprawdź moją aktualizację dotyczącą WinRT. – Noseratio