Parameter und Rückgabewerte für Multithreadprozeduren (C#)Parameters and Return Values for Multithreaded Procedures (C#)

Das Bereitstellen und Zurückgeben von Rückgabewerten in einer Multithreadanwendung ist kompliziert, weil der Konstruktor für die Threadklasse einen Verweis an eine Prozedur übergeben muss, die weder Argumente akzeptiert noch Werte zurückgibt.Supplying and returning values in a multithreaded application is complicated because the constructor for the thread class must be passed a reference to a procedure that takes no arguments and returns no value. Im folgenden Abschnitt werden ein paar einfache Methoden gezeigt, um Parameter und Rückgabewerte von Prozeduren in separaten Threads bereitzustellen.The following sections show some simple ways to supply parameters and return values from procedures on separate threads.

Bereitstellen von Parametern für MultithreadprozedurenSupplying Parameters for Multithreaded Procedures

Die beste Möglichkeit, um Parameter für ein Multithread-Methodenaufruf bereitzustellen ist, die Zielmethode in eine Klasse zu umschließen und Felder für diese Klasse zu definieren, die als Parameter für den neuen Thread dienen.The best way to supply parameters for a multithreaded method call is to wrap the target method in a class and define fields for that class that will serve as parameters for the new thread. Der Vorteil dieses Ansatzes ist, dass Sie jedes Mal, wenn Sie einen neuen Thread starten möchten, eine neue Instanz der Klasse mit eigenen Parametern erstellen können.The advantage of this approach is that you can create a new instance of the class, with its own parameters, every time you want to start a new thread. Nehmen wir z.B. an, dass Sie eine Funktion haben, die den Bereich eines Dreiecks wie im folgenden Code berechnet:For example, suppose you have a function that calculates the area of a triangle, as in the following code:

double CalcArea(double Base, double Height)  
{  
    return 0.5 * Base * Height;  
}  

Sie können eine Klasse schreiben, die die CalcArea-Funktion umschließt und Felder erstellt, um Eingabeparameter wie folgt zu speichern:You can write a class that wraps the CalcArea function and creates fields to store input parameters, as follows:

class AreaClass  
{  
    public double Base;  
    public double Height;  
    public double Area;  
    public void CalcArea()  
    {  
        Area = 0.5 * Base * Height;  
        MessageBox.Show("The area is: " + Area.ToString());  
    }  
}  

Sie können zum Verwenden von AreaClass ein AreaClass-Objekt erstellen und die Eigenschaften Base und Height so festlegen, wie es im folgenden Code gezeigt wird:To use the AreaClass, you can create an AreaClass object, and set the Base and Height properties as shown in the following code:

protected void TestArea()  
{  
    AreaClass AreaObject = new AreaClass();  

    System.Threading.Thread Thread =  
        new System.Threading.Thread(AreaObject.CalcArea);  
    AreaObject.Base = 30;  
    AreaObject.Height = 40;  
    Thread.Start();  
}  

Beachten Sie, dass die TestArea-Prozedur nicht den Wert des Area-Felds überprüft, nachdem sie die CalcArea-Methode aufgerufen hat.Notice that the TestArea procedure does not check the value of the Area field after calling the CalcArea method. Da CalcArea in einem separaten Thread ausgeführt wird, besteht keine Garantie, dass das Area-Feld festgelegt wird, wenn Sie es sofort nach dem Aufruf von Thread.Start überprüfen.Because CalcArea runs on a separate thread, the Area field is not guaranteed to be set if you check it immediately after calling Thread.Start. Im nächsten Abschnitt wird eine bessere Möglichkeit zum Zurückgeben von Werten aus Multithreadprozeduren beschrieben.The next section discusses a better way to return values from multithreaded procedures.

Rückgabe von Werten aus MultithreadprozedurenReturning Values from Multithreaded Procedures

Die Rückgabe von Werten aus Prozeduren, die in separaten Threads ausgeführt werden, wird dadurch erschwert, dass die Prozeduren weder Funktionen sein noch ByRef-Argumente verwenden können.Returning values from procedures that run on separate threads is complicated by the fact that the procedures cannot be functions and cannot use ByRef arguments. Die einfachste Möglichkeit zum Zurückgeben von Werten ist, indem Sie die BackgroundWorker-Komponente zum Verwalten Ihrer Threads verwenden und ein Ereignis auslösen, wenn die Aufgabe erledigt ist, und das Ergebnis mit einem Ereignishandler verarbeiten.The easiest way to return values is to use the BackgroundWorker component to manage your threads and raise an event when the task is done, and process the results with an event handler.

Im folgenden Beispiel wird ein Wert durch das Auslösen eines Ereignisses von einer Prozedur zurückgegeben, die in einem separaten Thread ausgeführt wird:The following example returns a value by raising an event from a procedure running on a separate thread:

class AreaClass2  
{  
    public double Base;  
    public double Height;  
    public double CalcArea()  
    {  
        // Calculate the area of a triangle.  
        return 0.5 * Base * Height;  
    }  
}  

private System.ComponentModel.BackgroundWorker BackgroundWorker1  
    = new System.ComponentModel.BackgroundWorker();  

private void TestArea2()  
{  
    InitializeBackgroundWorker();  

    AreaClass2 AreaObject2 = new AreaClass2();  
    AreaObject2.Base = 30;  
    AreaObject2.Height = 40;  

    // Start the asynchronous operation.  
    BackgroundWorker1.RunWorkerAsync(AreaObject2);  
}  

private void InitializeBackgroundWorker()  
{  
    // Attach event handlers to the BackgroundWorker object.  
    BackgroundWorker1.DoWork +=  
        new System.ComponentModel.DoWorkEventHandler(BackgroundWorker1_DoWork);  
    BackgroundWorker1.RunWorkerCompleted +=  
        new System.ComponentModel.RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted);  
}  

private void BackgroundWorker1_DoWork(  
    object sender,  
    System.ComponentModel.DoWorkEventArgs e)  
{  
    AreaClass2 AreaObject2 = (AreaClass2)e.Argument;  
    // Return the value through the Result property.  
    e.Result = AreaObject2.CalcArea();  
}  

private void BackgroundWorker1_RunWorkerCompleted(  
    object sender,  
    System.ComponentModel.RunWorkerCompletedEventArgs e)  
{  
    // Access the result through the Result property.  
    double Area = (double)e.Result;  
    MessageBox.Show("The area is: " + Area.ToString());  
}  

Sie können Parameter und Rückgabewerte bereitstellen, indem Sie die optionale Zustandsobjektvariable ByVal der QueueUserWorkItem-Methode zu verwenden.You can provide parameters and return values to thread-pool threads by using the optional ByVal state-object variable of the QueueUserWorkItem method. Threads des Threadzeitgebers unterstützen für diesen Zweck auch ein Zustandsobjekt.Thread-timer threads also support a state object for this purpose. Informationen über Threadpooling und Threadzeitgeber finden Sie unter Thread Pooling (C#) (Pooling von Threads (C#)) und Thread Timers (C#) (Threadzeitgeber (C#)).For information on thread pooling and thread timers, see Thread Pooling (C#) and Thread Timers (C#).

Siehe auchSee Also

Exemplarische Vorgehensweise: Multithreading mit der BackgroundWorker-Komponente (C#)Walkthrough: Multithreading with the BackgroundWorker Component (C#)
Thread Pooling (C#) (Pooling von Threads (C#))Thread Pooling (C#)
Threadsynchronisierung (C#)Thread Synchronization (C#)
EreignisseEvents
Multithreaded Applications (C#) (Multithreadanwendungen (C#))Multithreaded Applications (C#)
DelegatenDelegates
Multithreading in KomponentenMultithreading in Components