2011-09-02 7 views
12

Chcę zrobić coś takiego jak poniżej: zasadniczo wywołuję operację asynchroniczną, która wywoła wywołanie zwrotne w innym wątku i chcę poczekać, aż zakończy "inline". Obawiam się, że zmiany zmiennych udostępnianych w wątkach (zdarzenie bar &) mogą nie być synchronizowane, na przykład z powodu przechowywania w rejestrach. Jeśli były to zmienne składowe, mogłem oznaczyć je jako zmienne, ale zmienne nie mogą być używane w zmiennych lokalnych tworzonych na stosie. Mógłbym używać zmiennych członkowskich, ale myślę, że jego czystsze nie zaśmiecać mojej klasy, utrzymując to wszystko lokalne.Czy można bezpiecznie udostępniać zmienne lokalne między wątkami (przez zamknięcie wywołania zwrotnego)?

Bar bar = null; 
ManualResetEvent event = new ManualResetEvent(false); 

foo.AsyncOperation(new Action(()=>{  
    // This delegate will be called in another thread 
    bar = ... 
    event.Set(); 
})); 

event.WaitOne(timeout); 
// use bar 
+2

Uwaga: chyba zrobić coś innego między 'AsyncOperation' i' WaitOne', równie dobrze można go uruchomić synchronicznie –

+0

To pytanie jest związane: http://stackoverflow.com/questions/6581848/memory-barrier- generators/6932271 # 6932271 –

+0

@Marc - Dobry punkt, ale API nazywam z natury asynchroniczny. Jest oparty na wiadomościach przesyłanych przez sieć do serwera. W ramach AsyncOperaton ustawiona jest wiadomość, a oddzwonienie jest powiadamiane, gdy pojawia się odpowiedź. Używam go asynchronicznie przez większość czasu, ale w tym konkretnym przypadku chcę poczekać na wynik. Wrzucam do WaitOne czas na wypadek, gdyby odpowiedź nie nadeszła. – Shane

Odpowiedz

6

Tak, będzie działać poprawnie. Czytaj tutaj

http://www.albahari.com/threading/part4.aspx

The following implicitly generate full fences:Setting and waiting on a signaling construct

i sygnalizacji konstruuje ManualResetEvent jest włączone.

Jeśli chcesz wiedzieć, co full fence jest w tej samej strony:

Pełna ogrodzeń Najprostszym rodzajem bariery pamięci jest pełna pamięć barierą (pełne ogrodzenie), który zapobiega jakiejkolwiek nauczania reorganizację lub buforowanie wokół tego ogrodzenia. Wywołanie Thread.MemoryBarrier generuje pełne ogrodzenie ;

+0

Cool; jeśli "WaitOne" działa jako ogrodzenie, jest bezpieczne. Robię to jednak z tym, że MSDN dokumentowałaby tę http://msdn.microsoft.com/en-us/library/58195swd.aspx –

+2

@Marc Dokumentacja msdn o bezpieczeństwie wątków i płotach jest bardzo słaba, o ile dobrze pamiętam, ALE http://msdn.microsoft.com/en-us/library/ms686355(v=vs.85).aspx 'Następujące funkcje synchronizacji wykorzystują odpowiednie bariery do zapewnienia porządku pamięci:' 'Funkcje oczekiwania' i' Funkcje, które synchronizacja sygnałów obiektów ' – xanatos

+0

posortowana, a następnie; Ja usunę moją odpowiedź: –

4

myślę kod zadziała - zamknięcie podniesie następnie do sterty nawet gdyby były tylko stosu zmiennych (the ManualReseetEvent na pewno nie będzie).

Ale dlaczego nie położysz wszystkiego po zdarzeniu.WaitOne() tylko wewnątrz kontynuacji (blok był zdarzeniem. Zostało wywołane)? Myślę, że powinien to być preferowany sposób radzenia sobie z taką sytuacją i nie popadniesz w kłopoty w ten sposób (w ogóle nie potrzebujesz paska w bloku zewnętrznym, a nadal możesz używać MRE do sprawdzenia).

Zastanowiłabym się zamienić to w Operacje za pomocą obiektów Zadania - to rozwiązałoby to wszystko za jednym razem (na przykład zwróć zadanie z AsynocOperation). Następnie można czekać na wynik zadania i korzystać z wracającą Bar ...

class Foo 
{ 
// ... 
private Task<Bar> AsyncOperation(Task<Bar> initializeBar) 
{ 
    return initializeBar 
      .ContinueWith(
      bar => { 
        /* do your work with bar and return some new or same bar */ 
        return bar; 
        }); 
} 
} 

i używać go tak:

var task = foo.AsyncOperation(Taks.Factory.StartNew(() => { /* create and return a bar */ })); 
var theBar = task.Result; // <- this will wait for the task to finish 
// use your bar 

PS: Zamknięcie będzie w zasadzie tylko owinąć je w klasie -object;) PPS: ciężko mi przetestować ten kod bez AsyncOperation, ale powinien działać błędy składniowe modulo przez niewłaściwą pisownię/pisanie zrobiłem

+0

Nie jestem taki pewien - jak to jest * gwarantowane * do pracy? zwykłe reguły danych/zamówień obowiązują tylko wtedy, gdy jednowątkowe ... –

+0

oczywiście wiesz o nich więcej niż ja - pytanie było, czy ten kod jest wprowadzony do jakiegoś rejestru (i zakładałem), że zostanie ponownie użyty/odtworzony w drugim wątku) i myślę, że * to * na pewno się nie wydarzy. I myślę, że widziałem coś bardzo podobnego w asynchronicznej rzeczy, której używa F # i szczerze: użyłem podobnych rzeczy (używając ManualResetEvents - lokalnie zdefiniowanego do synchronizowania wątków) bardzo cicho i nigdy nie wpadam w kłopoty. Ale nie jestem concurency-Wizzard - może potrafisz wskazać, gdzie leży problem, zamiast na nim podpowiedzieć? (bez offensów - naprawdę zainteresowany) – Carsten

+0

oh czekaj - ty (oczywiście) myślisz o barze - obiekt, który chyba ... hmm - to może naprawdę oznaczać kłopoty ... – Carsten

Powiązane problemy