Partager via


Paramètres et valeurs de retour pour les procédures multithread (C# et Visual Basic)

L'apport et le retour des valeurs dans une application multithread se trouvent compliqués par le fait que le constructeur de la classe de thread doit recevoir une référence à une procédure qui n'accepte aucun argument et ne retourne aucune valeur. Les sections ci-dessous indiquent quelques méthodes simples pour fournir des paramètres et retourner des valeurs à partir de procédures sur des threads séparés.

Apport de paramètres pour des procédures multithread

Le meilleur moyen de fournir des paramètres pour un appel de méthode multithread consiste à placer la méthode cible dans une classe et à définir pour cette classe des champs qui vont servir de paramètres pour le nouveau thread. Cette approche présente l'avantage de vous permettre de créer une nouvelle instance de la classe, avec ses propres paramètres, à chaque fois que vous voulez démarrer un nouveau thread. Prenons l'exemple d'une fonction calculant la surface d'un triangle, comme dans le code suivant :

Function CalcArea(ByVal Base As Double, ByVal Height As Double) As Double
    CalcArea = 0.5 * Base * Height
End Function
double CalcArea(double Base, double Height)
{
    return 0.5 * Base * Height;
}

Vous pouvez écrire une classe qui contient la fonction CalcArea et crée des champs pour stocker les paramètres d'entrée, comme suit :

Class AreaClass
    Public Base As Double
    Public Height As Double
    Public Area As Double
    Sub CalcArea()
        Area = 0.5 * Base * Height
        MessageBox.Show("The area is: " & Area.ToString)
    End Sub
End Class
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());
    }
}

Pour utiliser AreaClass, vous pouvez créer un objet AreaClass et définir les propriétés Base et Height conformément au code suivant :

Protected Sub TestArea()
    Dim AreaObject As New AreaClass
    Dim Thread As New System.Threading.Thread(
                        AddressOf AreaObject.CalcArea)
    AreaObject.Base = 30
    AreaObject.Height = 40
    Thread.Start()
End Sub
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();
}

Vous remarquerez que la procédure TestArea ne vérifie pas la valeur du champ Area après avoir appelé la méthode CalcArea. Comme CalcArea s'exécute sur un thread séparé, le paramétrage du champ Area n'est pas garanti si vous le vérifiez immédiatement après avoir appelé Thread.Start. La section suivante indique une meilleure méthode pour retourner des valeurs à partir de procédures multithread.

Retour de valeurs à partir de procédures multithread

Le retour de valeurs à partir de procédures qui s'exécutent sur des threads séparés est compliqué par le fait que les procédures ne peuvent ni être des fonctions, ni utiliser des arguments ByRef. La méthode la plus facile pour retourner des valeurs consiste à utiliser le composant BackgroundWorker pour gérer vos threads, à déclencher un événement à la fin de la tâche et à traiter les résultats avec un gestionnaire d'événements.

L'exemple ci-dessous retourne une valeur en déclenchant un événement à partir d'une procédure s'exécutant sur un thread séparé :

Private Class AreaClass2
    Public Base As Double
    Public Height As Double
    Function CalcArea() As Double
        ' Calculate the area of a triangle.
        Return 0.5 * Base * Height
    End Function
End Class

Private WithEvents BackgroundWorker1 As New System.ComponentModel.BackgroundWorker

Private Sub TestArea2()
    Dim AreaObject2 As New AreaClass2
    AreaObject2.Base = 30
    AreaObject2.Height = 40

    ' Start the asynchronous operation.
    BackgroundWorker1.RunWorkerAsync(AreaObject2)
End Sub

' This method runs on the background thread when it starts.
Private Sub BackgroundWorker1_DoWork(
    ByVal sender As Object, 
    ByVal e As System.ComponentModel.DoWorkEventArgs
    ) Handles BackgroundWorker1.DoWork

    Dim AreaObject2 As AreaClass2 = CType(e.Argument, AreaClass2)
    ' Return the value through the Result property.
    e.Result = AreaObject2.CalcArea()
End Sub

' This method runs on the main thread when the background thread finishes.
Private Sub BackgroundWorker1_RunWorkerCompleted(
    ByVal sender As Object,
    ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs
    ) Handles BackgroundWorker1.RunWorkerCompleted

    ' Access the result through the Result property.
    Dim Area As Double = CDbl(e.Result)
    MessageBox.Show("The area is: " & Area.ToString)
End Sub
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());
}

Vous pouvez fournir des paramètres et des valeurs de retour aux threads ThreadPool à l'aide de la variable objet état ByVal (facultative) de la méthode QueueUserWorkItem. Les threads de type composant Timer thread prennent également en charge un objet état à cet effet. Pour plus d'informations sur le regroupement des threads et les composants Timer thread, consultez Mise en pool de threads (C# et Visual Basic) et Composants Timer thread (C# et Visual Basic).

Voir aussi

Tâches

Procédure pas à pas : multithreading avec le composant BackgroundWorker (C# et Visual Basic)

Référence

Synchronisation des threads (C# et Visual Basic)

Événements (Guide de programmation C#)

Délégués (guide de programmation C#)

Concepts

Mise en pool de threads (C# et Visual Basic)

Applications multithread (C# et Visual Basic)

Autres ressources

Événements (Visual Basic)

Délégués (Visual Basic)

Multithreading dans les composants