Passer des paramètres aux threads

On désire souvent passer des paramètres à un thread (comme des données à manipuler, une file à attendre...). Le delegate ThreadStart ne prend aucun paramètre, donc si vous voulez créer votre propre thread, les informations à passer en paramètres doivent être stockées ailleurs. Le plus souvent, cela implique la création d'une nouvelle instance de classe et le stockage des informations dans cette nouvelle instance. La classe elle-même peut contenir le delegate qui sera utilisé pour démarrer le thread. Par exemple si l'on veut concevoir un programme qui a besoin de récupérer le contenu de plusieurs URLs, et cela en tâche de fond, on pourrait alors écrire un code qui ressemble à cela :

public class UrlFetcher
{
    string url

    public UrlFetcher (string url)
    {
        this.url = url;
    }

    public void Fetch()
    {
        // utilisation de la variable url
    }
}

[... dans une classe différente ...]

UrlFetcher fetcher = new UrlFetcher (myUrl);
new Thread (new ThreadStart (fetcher.Fetch)).Start();

Dans certains cas, l'on a seulement besoin d'appeler une méthode dans une classe (qui peut être la classe courante) avec un paramètre spécifique. Dans ce cas on peut vouloir utiliser une classe interne pour faire cet appel (avec l'état stocké dans la classe) et le delegate utilisé pour démarrer le thread appel simplement la "vraie" méthode avec les paramètres appropriés. A noter que l'objet sur lequel on appelle la méthode, sera aussi requit comme paramètre sauf si la méthode est statique (méthode de classe).

Utilisation du ThreadPool

L'une des alternatives à l'utilisation du delegate ThreadStart et d'utiliser le ThreadPool, soit en utilisant ThreadPool.QueueUserWorkItem ou en appelant un delegate de façon asynchrone. Ces deux méthodes seront abordées plus tard dans une section dédiée aux ThreadPool qui contient des exemples. Notez que l'appel d'un delegate de façon asynchrone vous permet de spécifier plusieurs paramètres fortement typés.

Solution 1 avec .NET 2.0 : les méthodes anonymes (avec ou sans le ThreadPool)

Les méthodes anonymes font parties des améliorations du C# dans .NET 2.0. Elles vous permettent d'écrire une méthode à l'intérieur d'une autre méthode, et d'utiliser cette méthode "interne" comme un delegate. Vous pouvez alors accéder aux variables locales et paramètres de la méthode "externe", dans la méthode anonyme. Exemple de l'utilisation d'une méthode anonyme pour récupérer une URL avec un delegate ThreadStart normal (utilisant aussi l'inférence du type delegate) :

ThreadStart starter = delegate { Fetch (myUrl); };
new Thread(starter).Start();

La création du thread et du delegate aurait peut-être faite en une seule étape, sur la même ligne, mais je pense que la présentation ci-dessus est plus lisible. Voici un code similaire qui utilise WaitCallback et place le job dans le ThreadPool.

WaitCallback callback = delegate (object state) { Fetch ((string)state); };
ThreadPool.QueueUserWorkItem (callback, myUrl);

Notez la façon dont l'état est déclaré.

Solution 2 avec .NET 2.0 : ParameterizedThreadStart

ParameterizedThreadStart est un nouveau delegate en .NET 2.0 qui prend un paramètre de type object. Vous pouvez créer un thread en utilisant une instance de ce delegate plutôt qu'utiliser ThreadStart, et une nouvelle surcharge de Thread.Start vous permet de spécifier la valeur à passer au thread. Cette méthode est simple mais n'accepte qu'un seul paramètre qui n'est pas fortement typé (comme avec l'utilisation du ThreadPool). Le code précédent peut être ré-écrit ainsi :

[Dans une méthode ou ailleurs]
Thread t = new Thread (new ParameterizedThreadStart(FetchUrl));
t.Start (myUrl);

[Et la méthode réel...]
static void FetchUrl(object url)
{
    // utilisation de la variable url, probablement en la castant avant
}

Page suivante : Accès concurrents aux données et verrouillages
Page précédente : Introduction


Lire la version originale de cette page

Revenir sur la page d'accueil de sylvain114