Eine der einfachsten Möglichkeiten, einen Rückgabewert von einem Thread abzurufen, ist die Verwendung von Verschlüssen. Erstellen Sie eine Variable, die den Rückgabewert des Threads enthält, und erfassen Sie ihn dann in einem Lambda-Ausdruck. Weisen Sie dieser Variablen aus dem Arbeitsthread den Wert "return" zu. Sobald dieser Thread endet, können Sie ihn aus dem übergeordneten Thread verwenden.
void Main()
{
object value = null; // Used to store the return value
var thread = new Thread(
() =>
{
value = "Hello World"; // Publish the return value
});
thread.Start();
thread.Join();
Console.WriteLine(value); // Use the return value here
}
lock(value) { value = "Hello world"; }
besser, mit dem Schreiben mehrerer Thread-Werte umzugehen?value
gleichzeitig ausgeführt werden. Aber denken Sie immer daran, wann ein Schloss notwendig ist.Ich würde den BackgroundWorker- Ansatz verwenden und das Ergebnis in e.Result zurückgeben.
BEARBEITEN:
Dies ist normalerweise mit WinForms und WPF verbunden, kann jedoch von jeder Art von .NET-Anwendung verwendet werden. Hier ist Beispielcode für eine Konsolen-App, die BackgroundWorker verwendet:
Ausgabe:
UPDATE 2014
Siehe @ Rogers Antwort unten.
https://stackoverflow.com/a/24916747/141172
Er weist darauf hin, dass Sie eine Aufgabe verwenden können, die a zurückgibt
Task<T>
, und überprüfenTask<T>.Result
.quelle
Dies hängt davon ab, wie Sie den Thread und die verfügbare .NET-Version erstellen möchten:
.NET 2.0+:
A) Sie können das
Thread
Objekt direkt erstellen . In diesem Fall könnten Sie "Schließung" verwenden - deklarieren Sie die Variable und erfassen Sie sie mit dem Lambda-Ausdruck:B) Sie können Delegaten und
IAsyncResult
und Rückgabewert vonEndInvoke()
Methode verwenden:C) Sie können
BackgroundWorker
Klasse verwenden. In diesem Fall können Sie eine erfasste Variable (wie bei einemThread
Objekt) oder ein Handle-RunWorkerCompleted
Ereignis verwenden:.NET 4.0+:
Ab .NET 4.0 können Sie die Task Parallel Library und die
Task
Klasse verwenden, um Ihre Threads zu starten. Mit der generischen KlasseTask<TResult>
können Sie den Rückgabewert von derResult
Eigenschaft abrufen:.NET 4.5+:
Ab .NET 4.5 können Sie auch
async
/await
keywords verwenden, um den Wert direkt von der Aufgabe zurückzugeben, anstatt dieResult
Eigenschaft zu erhalten:Hinweis: Die Methode, die den obigen Code enthält, sollte mit markiert werden
async
Schlüsselwort gekennzeichnet werden.Aus vielen Gründen ist die Verwendung der Task Parallel Library die bevorzugte Methode zum Arbeiten mit Threads.
quelle
Ein Thread ist keine Methode - normalerweise "geben" Sie keinen Wert zurück.
Wenn Sie jedoch versuchen, einen Wert aus den Ergebnissen einer Verarbeitung zurückzugewinnen, stehen Ihnen viele Optionen zur Verfügung. Die beiden wichtigsten sind:
Es hängt wirklich davon ab, wie Sie den Thread erstellen und wie Sie ihn verwenden möchten sowie von der Sprache / dem Framework / den Tools, die Sie verwenden.
quelle
Meine Lieblingsklasse führt eine beliebige Methode in einem anderen Thread mit nur 2 Codezeilen aus.
Verwendung
Beachten Sie, dass longFunctionComplete NICHT im selben Thread wie starthework ausgeführt wird.
Für Methoden, die Parameter annehmen, können Sie jederzeit Closures verwenden oder die Klasse erweitern.
quelle
Hier ist ein einfaches Beispiel mit einem Delegaten ...
Es gibt eine großartige Serie zum Thema Threading bei Threading in C # .
quelle
Verwenden Sie einfach den Delegatenansatz.
Stellen Sie nun die Multiplikationsfunktion ein, die für einen anderen Thread funktioniert:
quelle
Ich bin auf diesen Thread gestoßen, als ich auch versucht habe, den Rückgabewert einer Methode zu erhalten, die in einem Thread ausgeführt wird. Ich dachte, ich würde meine Lösung veröffentlichen, die funktioniert.
Diese Lösung verwendet eine Klasse, um sowohl die auszuführende Methode (indirekt) als auch den Rückgabewert zu speichern. Die Klasse kann für jede Funktion und jeden Rückgabetyp verwendet werden. Sie instanziieren das Objekt einfach mit dem Rückgabewerttyp und übergeben dann die aufzurufende Funktion über ein Lambda (oder einen Delegaten).
C # 3.0-Implementierung
Um diesen Code zu verwenden, können Sie einen Lambda (oder einen Delegaten) verwenden. Hier ist das Beispiel mit Lambdas:
Implementierung von VB.NET 2008
Jeder, der VB.NET 2008 verwendet, kann keine Lambdas mit nicht wertvollen Rückgabemethoden verwenden. Dies wirkt sich auf die
ThreadedMethod
Klasse aus, daher wirdExecuteMethod
der Wert der Funktion zurückgegeben. Das tut nichts weh.quelle
Mit dem neuesten .NET Framework ist es möglich, einen Wert aus einem separaten Thread mithilfe einer Aufgabe zurückzugeben, wobei die Result-Eigenschaft den aufrufenden Thread blockiert, bis die Aufgabe abgeschlossen ist:
Weitere Informationen finden Sie unter http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx
quelle
ThreadStart-Delegaten in C #, die zum Starten von Threads verwendet werden, haben den Rückgabetyp 'void'.
Wenn Sie einen 'Rückgabewert' von einem Thread erhalten möchten, sollten Sie an einen freigegebenen Speicherort schreiben (in geeigneter threadsicherer Weise) und daraus lesen, wenn der Thread die Ausführung abgeschlossen hat.
quelle
Wenn Sie keinen BackgroundWorker verwenden möchten und nur einen regulären Thread verwenden möchten, können Sie ein Ereignis auslösen, um Daten wie folgt zurückzugeben:
quelle
thread1_
Teil seiner Verkabelung des AsyncCompletedEventHandler weggelassen . Wenn meine Bearbeitung fehlerhaft war, helfen Sie mir bitte zu verstehen, was dort vor sich ging.thread1_Thread1Completed +=
dathread1_Thread1Completed
es sich um den Namen einer Funktion handelt. Sie können ihn also nicht auf der linken Seite eines Zuweisungsoperators platzieren. Die linke SeiteThread1Completed +=
wird verwendet, da dies ein Ereignis ist. Daher kann es auf der linken Seite des Zuweisungsoperators angezeigt werden, um Ereignishandler hinzuzufügen. Siehepublic event AsyncCompletedEventHandler Thread1Completed;
#region
Sektion vorher nicht sehen konnte . Ich schaute. Ehrlich! :)Threads haben nicht wirklich Rückgabewerte. Wenn Sie jedoch einen Delegaten erstellen, können Sie ihn über die
BeginInvoke
Methode asynchron aufrufen . Dadurch wird die Methode in einem Thread-Pool-Thread ausgeführt. Sie können einen beliebigen Rückgabewert erhalten, z. B. einen Anruf überEndInvoke
.Beispiel:
GetAnswer
wird in einem Thread-Pool-Thread ausgeführt und wenn Sie fertig sind, können Sie die Antwort überEndInvoke
wie gezeigt abrufen .quelle
Der BackgroundWorker ist hilfreich bei der Entwicklung für Windows Forms.
Angenommen, Sie wollten eine einfache Klasse hin und her bestehen:
Ich habe eine kurze Klasse geschrieben, die Folgendes macht:
Aus der Thread-Routine heraus:
Das Hinzufügen eines Delegaten kann nützlich sein, um Ihre Daten direkt in Ihren Hauptthread zurückzusenden. Möglicherweise müssen Sie jedoch Invoke verwenden, wenn einige der Datenelemente nicht threadsicher sind.
Um dies zu testen, erstellen Sie eine kleine Konsolenanwendung und fügen Sie diese in die Datei Program.cs ein :
Hier ist ein Screenshot von dem, was ich damit bekommen habe:
Ich hoffe, andere können verstehen, was ich zu erklären versucht habe.
Ich arbeite gerne an Threads und benutze Delegierte. Sie machen C # viel Spaß.
Anhang: Für VB-Codierer
Ich wollte sehen, worum es beim Schreiben des obigen Codes als VB-Konsolenanwendung geht. Die Konvertierung beinhaltete einige Dinge, die ich nicht erwartet hatte, daher werde ich diesen Thread hier für diejenigen aktualisieren, die wissen möchten, wie man VB einfädelt.
quelle
quelle
test(){ Thread.Sleep(5000); /*Highly time demanding process*/ return "Returned from test()";}
. In diesem Fall hätte der eigenständige Thread keine Zeit, derreturnValue
Variablen einen neuen Wert zuzuweisen . Als letzten Ausweg können Sie eine Thread-Referenz speichernvar standaloneThread = new Thread(()=> //...);
und anschließend synchron startenstandaloneThread.Start(); standaloneThread.Join();
. Dies ist jedoch sicherlich nicht die beste Vorgehensweise.Eine einfache Lösung besteht darin, einen Parameter per ref an die im Thread ausgeführte Funktion zu übergeben und seinen Wert im Thread zu ändern.
Wenn Sie die Funktion, die im Profil ausgeführt wird, nicht ändern können, können Sie eine andere Funktion einschließen:
quelle
Kann diesen Code verwenden:
quelle
Ich bin kein Experte für Threading, deshalb habe ich es so gemacht:
Ich habe eine Einstellungsdatei erstellt und
Im neuen Thread:
Dann nehme ich diesen Wert auf, wann immer ich ihn brauche.
quelle