Jak zwrócić wartość z wątku?
c#
.net
multithreading
Sam
źródło
źródło
lock(value) { value = "Hello world"; }
byłoby lepiej w obsłudze zapisu wartości wielu wątków?value
w tym samym czasie. Ale tak, zawsze uważaj, kiedy zamek jest konieczny.Zależy to od tego, jak chcesz utworzyć wątek i dostępnej wersji .NET:
.NET 2.0+:
A) Możesz stworzyć
Thread
obiekt bezpośrednio. W tym przypadku możesz użyć "zamknięcia" - zadeklaruj zmienną i przechwyć ją za pomocą wyrażenia lambda:B) Możesz użyć delegatów
IAsyncResult
i zwrócić wartość zEndInvoke()
metody:C) Możesz użyć
BackgroundWorker
class. W tym przypadku możesz użyć przechwyconej zmiennej (jak w przypadkuThread
obiektu) lub obsłużyćRunWorkerCompleted
zdarzenie:.NET 4.0+:
Począwszy od .NET 4.0, możesz użyć biblioteki równoległej zadań i
Task
klasy, aby rozpocząć wątki. Klasa generycznaTask<TResult>
pozwala na pobranie wartości zwracanej zResult
właściwości:.NET 4.5+:
Począwszy od .NET 4.5 można również użyć
async
/await
words do bezpośredniego zwracania wartości z zadania zamiast uzyskiwaniaResult
właściwości:Uwaga: metodę zawierającą powyższy kod należy oznaczyć
async
słowem kluczowym.Z wielu powodów preferowanym sposobem pracy z wątkami jest użycie biblioteki równoległej zadań.
źródło
Chciałbym użyć BackgroundWorker podejście i zwraca wynik w e.Result.
EDYTOWAĆ:
Jest to często kojarzone z WinForms i WPF, ale może być używane przez dowolny typ aplikacji .NET. Oto przykładowy kod aplikacji konsoli korzystającej z BackgroundWorker:
Wynik:
AKTUALIZACJA 2014
Zobacz odpowiedź @ Rogera poniżej.
https://stackoverflow.com/a/24916747/141172
Wskazuje, że możesz użyć zadania, które zwraca a
Task<T>
i sprawdzićTask<T>.Result
.źródło
Wątek nie jest metodą - normalnie nie „zwracasz” wartości.
Jeśli jednak próbujesz odzyskać wartość z wyników jakiegoś przetwarzania, masz wiele opcji, z których dwie główne to:
To naprawdę zależy od tego, jak tworzysz wątek i jak chcesz go używać, a także od języka / frameworka / narzędzi, których używasz.
źródło
Moja ulubiona klasa uruchamia dowolną metodę w innym wątku z zaledwie 2 wierszami kodu.
stosowanie
Uważaj, że longFunctionComplete NIE zostanie wykonany w tym samym wątku, co starthework.
W przypadku metod, które przyjmują parametry, zawsze możesz użyć domknięć lub rozwinąć klasę.
źródło
Oto prosty przykład wykorzystujący delegata ...
W Threading w C # jest niesamowita seria dotycząca wątków .
źródło
Po prostu użyj podejścia delegata.
Teraz utwórz funkcję Multiply, która będzie działać w innym wątku:
źródło
Natknąłem się na ten wątek, próbując również uzyskać wartość zwracaną metody, która jest wykonywana w ramach wątku. Pomyślałem, że opublikuję moje rozwiązanie, które działa.
To rozwiązanie wykorzystuje klasę do przechowywania zarówno metody do wykonania (pośrednio), jak i przechowuje zwracaną wartość. Klasa może być używana dla dowolnej funkcji i dowolnego typu zwracanego. Po prostu tworzysz instancję obiektu przy użyciu zwracanego typu wartości, a następnie przekazujesz funkcję do wywołania za pośrednictwem lambda (lub delegata).
Implementacja C # 3.0
Aby użyć tego kodu, możesz użyć Lambda (lub delegata). Oto przykład wykorzystujący lambdy:
Wdrożenie VB.NET 2008
Nikt, kto używa VB.NET 2008, nie może używać lambd z metodami zwracającymi niezwiązane z wartością. Ma to wpływ na
ThreadedMethod
klasę, więc zwrócimyExecuteMethod
wartość funkcji. To niczego nie boli.źródło
W najnowszej wersji .NET Framework możliwe jest zwrócenie wartości z oddzielnego wątku za pomocą zadania, w którym właściwość Result blokuje wątek wywołujący do momentu zakończenia zadania:
Aby uzyskać szczegółowe informacje, zobacz http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx
źródło
Delegaty ThreadStart w C # używane do uruchamiania wątków mają zwracany typ „void”.
Jeśli chcesz uzyskać `` wartość zwracaną '' z wątku, powinieneś napisać do udostępnionej lokalizacji (w odpowiedni sposób bezpieczny dla wątków) i odczytać z niej, gdy wątek zakończy wykonywanie.
źródło
Jeśli nie chcesz używać BackgroundWorkera i po prostu używasz zwykłego wątku, możesz uruchomić zdarzenie, aby zwrócić takie dane:
źródło
thread1_
że pominąłeś część jego okablowania AsyncCompletedEventHandler . Jeśli moja zmiana była błędna, pomóż mi zrozumieć, co się tam dzieje.thread1_Thread1Completed +=
ponieważthread1_Thread1Completed
jest to nazwa funkcji, więc nie możesz jej umieścić po lewej stronie operatora przypisania. Lewa stronaThread1Completed +=
jest używana, ponieważ jest to zdarzenie, więc może pojawić się po lewej stronie operatora przypisania, aby dodać programy obsługi zdarzeń. Zobaczpublic event AsyncCompletedEventHandler Thread1Completed;
#region
sekcji. Spojrzałem. Szczery! :)Wątki tak naprawdę nie zwracają wartości. Jeśli jednak utworzysz delegata, możesz wywołać go asynchronicznie za pomocą
BeginInvoke
metody. Spowoduje to wykonanie metody w wątku puli wątków. Możesz uzyskać dowolną wartość zwracaną z, na przykład call viaEndInvoke
.Przykład:
GetAnswer
wykona w wątku puli wątków, a po zakończeniu możesz pobrać odpowiedź,EndInvoke
jak pokazano.źródło
BackgroundWorker jest miła przy opracowywaniu dla Windows Forms.
Powiedzmy, że chcesz zaliczyć proste zajęcia w tę iz powrotem:
Napisałem krótkie zajęcia, które obejmują:
Od wewnątrz procedury wątku:
Dodanie delegata może być przydatne do wysyłania danych bezpośrednio z powrotem do głównego wątku, ale może być konieczne użycie Invoke, jeśli niektóre elementy danych nie są bezpieczne dla wątków.
Aby to przetestować, utwórz małą aplikację konsolową i umieść ją w pliku Program.cs :
Oto zrzut ekranu tego, co mam z tym:
Mam nadzieję, że inni zrozumieją to, co próbowałem wyjaśnić.
Lubię pracować nad wątkami i korzystać z delegatów. Sprawiają, że C # jest świetną zabawą.
Dodatek: dla koderów VB
Chciałem zobaczyć, co wymagało napisania powyższego kodu jako aplikacji konsoli VB. Konwersja obejmowała kilka rzeczy, których się nie spodziewałem, więc zaktualizuję ten wątek tutaj dla tych, którzy chcą wiedzieć, jak wątkować w VB.
źródło
źródło
test(){ Thread.Sleep(5000); /*Highly time demanding process*/ return "Returned from test()";}
. W takim przypadku samodzielny wątek nie miałby czasu na przypisanie nowej wartości doreturnValue
zmiennej. W ostateczności możesz zapisać odwołanie do wątku,var standaloneThread = new Thread(()=> //...);
a następnie uruchomić je w zsynchronizowany sposóbstandaloneThread.Start(); standaloneThread.Join();
. Ale z pewnością nie jest to najlepsza praktyka.Prostym rozwiązaniem jest przekazanie parametru przez ref do funkcji działającej w wątku i zmiana jego wartości w wątku.
Jeśli nie możesz zmienić funkcji działającej w bieżniku, możesz zawinąć ją w inną funkcję:
źródło
Może używać tego kodu:
źródło
Nie jestem ekspertem w gwintowaniu, dlatego zrobiłem to tak:
Utworzyłem plik ustawień i
W nowym wątku:
Potem zbieram tę wartość, kiedy jej potrzebuję.
źródło