web-dev-qa-db-fra.com

Comment exécuter un simple morceau de code dans un nouveau thread?

J'ai un peu de code que je dois exécuter dans un thread différent de celui de l'interface graphique, car il provoque actuellement le gel du formulaire pendant l'exécution du code (environ 10 secondes).

Supposons que je n’ai jamais créé de nouveau fil avant; Qu'est-ce qu'un exemple simple/basique de comment faire cela en C # et en utilisant .NET Framework 2.0 ou version ultérieure?

319
Tim M

Un bon endroit pour commencer à lire est Joe Albahari .

Si vous voulez créer votre propre fil, c'est aussi simple que cela:

using System.Threading;
new Thread(() => 
{
    Thread.CurrentThread.IsBackground = true; 
    /* run your code here */ 
    Console.WriteLine("Hello, world"); 
}).Start();
312
Ed Power

BackgroundWorker semble être le meilleur choix pour vous.

Voici mon exemple minimal. Après avoir cliqué sur le bouton, l’agent d’arrière-plan commencera à travailler dans le fil d’arrière-plan et rendra également compte de sa progression simultanément. Il fera également rapport une fois le travail terminé.

using System.ComponentModel;
...
    private void button1_Click(object sender, EventArgs e)
    {
        BackgroundWorker bw = new BackgroundWorker();

        // this allows our worker to report progress during work
        bw.WorkerReportsProgress = true;

        // what to do in the background thread
        bw.DoWork += new DoWorkEventHandler(
        delegate(object o, DoWorkEventArgs args)
        {
            BackgroundWorker b = o as BackgroundWorker;

            // do some simple processing for 10 seconds
            for (int i = 1; i <= 10; i++)
            {
                // report the progress in percent
                b.ReportProgress(i * 10);
                Thread.Sleep(1000);
            }

        });

        // what to do when progress changed (update the progress bar for example)
        bw.ProgressChanged += new ProgressChangedEventHandler(
        delegate(object o, ProgressChangedEventArgs args)
        {
            label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
        });

        // what to do when worker completes its task (notify the user)
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
        delegate(object o, RunWorkerCompletedEventArgs args)
        {
            label1.Text = "Finished!";
        });

        bw.RunWorkerAsync();
    }

Note:

  • Je mets tout en méthode simple en utilisant la méthode anonyme de C # pour plus de simplicité, mais vous pouvez toujours les extraire de différentes méthodes.
  • Il est prudent de mettre à jour l'interface graphique dans les gestionnaires ProgressChanged ou RunWorkerCompleted. Cependant, la mise à jour de l'interface graphique à partir de DoWork provoquera InvalidOperationException.
191
Gant

Le ThreadPool.QueueUserWorkItem est assez idéal pour quelque chose de simple. Le seul inconvénient est d'accéder à un contrôle de l'autre thread.

System.Threading.ThreadPool.QueueUserWorkItem(delegate {
    DoSomethingThatDoesntInvolveAControl();
}, null);
97
Mark Brackett

Rapide et sale, mais ça va marcher:

Utilisation en haut:

using System.Threading;

code simple:

static void Main( string[] args )
{
    Thread t = new Thread( NewThread );
    t.Start();
}

static void NewThread()
{
    //code goes here
}

Je viens de jeter cela dans une nouvelle application de la console pour un exemple

74
FallenAvatar

Voici une autre option:

Task.Run(()=>{
//Here is a new thread
});
61
Spongebob Comrade

Essayez d’utiliser la classe BackgroundWorker . Vous lui donnez des délégués pour savoir quoi exécuter et pour être averti lorsque le travail est terminé. Il y a un exemple sur la page MSDN auquel j'ai lié.

40
Andy

Si vous voulez obtenir une valeur:

var someValue;

Thread thread = new Thread(delegate()
            {                 
                //Do somthing and set your value
                someValue = "Hello World";
            });

thread.Start();

while (thread.IsAlive)
  Application.DoEvents();
14
Starkey

Placez ce code dans une fonction (le code qui ne peut pas être exécuté sur le même thread que l'interface graphique), et pour déclencher l'exécution de ce code, mettez ce qui suit.

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

L'appel de la fonction de démarrage sur l'objet thread entraînera l'exécution de votre appel de fonction dans un nouveau thread.

6
Redbaron

Voici comment utiliser des threads avec un progressBar, son juste pour comprendre comment les threads fonctionnent, sous la forme il y a trois progressBar et 4 boutons:

 public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    Thread t, t2, t3;
    private void Form1_Load(object sender, EventArgs e)
    {

        CheckForIllegalCrossThreadCalls = false;

         t = new Thread(birinicBar); //evry thread workes with a new progressBar


         t2 = new Thread(ikinciBar);


         t3 = new Thread(ucuncuBar);

    }

    public void birinicBar() //to make progressBar work
    {
        for (int i = 0; i < 100; i++) {
            progressBar1.Value++;
            Thread.Sleep(100); // this progressBar gonna work faster
        }
    }

    public void ikinciBar()
    {
        for (int i = 0; i < 100; i++)
        {
            progressBar2.Value++;
            Thread.Sleep(200);
        }


    }

    public void ucuncuBar()
    {
        for (int i = 0; i < 100; i++)
        {
            progressBar3.Value++;
            Thread.Sleep(300);
        }
    }

    private void button1_Click(object sender, EventArgs e) //that button to start the threads
    {
        t.Start();
        t2.Start(); t3.Start();

    }

    private void button4_Click(object sender, EventArgs e)//that button to stup the threads with the progressBar
    {
        t.Suspend();
        t2.Suspend();
        t3.Suspend();
    }

    private void button2_Click(object sender, EventArgs e)// that is for contuniue after stuping
    {
        t.Resume();
        t2.Resume();
        t3.Resume();
    }

    private void button3_Click(object sender, EventArgs e) // finally with that button you can remove all of the threads
    {
        t.Abort();
        t2.Abort();
        t3.Abort();
    }
}
4
Ammar Alyasry
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime, 
                                            DateTime procDateTime);

// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);

Charles votre code (ci-dessus) n'est pas correct. Vous n'avez pas besoin de tourner en attente de l'achèvement. EndInvoke bloquera jusqu'à ce que WaitHandle soit signalé.

Si vous voulez bloquer jusqu'à la fin, vous devez simplement

nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null));

ou bien

ar.AsyncWaitHandle.WaitOne();

Mais à quoi sert-il d’émettre des appels anyc si vous bloquez? Vous pouvez aussi bien utiliser un appel synchrone. Un meilleur pari serait de ne pas bloquer et passer dans un lambda pour le nettoyage:

nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);

Une chose à garder à l'esprit est que vous devez appelez EndInvoke. Beaucoup de gens l'oublient et finissent par laisser fuir WaitHandle car la plupart des implémentations asynchrones publient l'attente dans EndInvoke.

3
Matt Davison

Si vous envisagez d'utiliser l'objet Thread brut, vous devez définir IsBackground sur true au minimum et définir le modèle Threading Apartment (probablement STA).

public static void DoWork()
{
    // do some work
}

public static void StartWorker()
{
    Thread worker = new Thread(DoWork);
    worker.IsBackground = true;
    worker.SetApartmentState(System.Threading.ApartmentState.STA);
    worker.Start()
}

Je recommanderais la classe BackgroundWorker si vous avez besoin d'interaction avec l'interface utilisateur.

2
user50612

Il existe de nombreuses manières d’exécuter des threads distincts en .Net, chacun ayant des comportements différents. Avez-vous besoin de continuer à exécuter le fil après la fermeture de l'interface graphique? Avez-vous besoin de transmettre des informations entre le fil et l'interface graphique? Le fil doit-il mettre à jour l'interface graphique? Le thread doit-il alors quitter une tâche ou doit-il continuer à s'exécuter? Les réponses à ces questions vous indiqueront quelle méthode utiliser.

Il existe un bon article article sur la méthode asynchrone sur le site Web de Code Project, qui décrit les différentes méthodes et fournit un exemple de code.

Notez que cet article a été écrit avant le modèle async/wait et Bibliothèque de tâches parallèle ont été introduits dans .NET.

1
Dour High Arch

une autre option, qui utilise des délégués et le pool de threads ...

en supposant que 'GetEnergyUsage' est une méthode qui prend un DateTime et un autre DateTime en tant qu'arguments en entrée, et retourne un ...

// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime, 
                                            DateTime procDateTime);

// following inside of some client method 
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;                     
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
1
Charles Bretana

Comment: utiliser un fil de discussion pour rechercher des fichiers

Vous devez être très prudent avec l'accès d'autres threads à des éléments spécifiques à l'interface graphique (il est courant pour de nombreux toolkits d'interface graphique). Si vous voulez mettre à jour quelque chose dans l'interface graphique à partir du traitement de la vérification du fil cette réponse , je pense que c'est utile pour WinForms. Pour WPF, voir this (il montre comment toucher un composant dans la méthode UpdateProgress () afin qu'il fonctionne à partir d'autres threads, mais en réalité, je n'aime pas le fait qu'il ne fasse pas CheckAccess() avant de faire BeginInvoke via Dispathcer, see et recherchez CheckAccess dans celui-ci)

Je cherchais un livre spécifique à .NET sur le filetage et trouvé celui-ci (téléchargeable gratuitement). Voir http://www.albahari.com/threading/ pour plus de détails à ce sujet.

Je pense que vous trouverez ce dont vous avez besoin pour lancer l’exécution en tant que nouveau fil dans les 20 premières pages et qu’il en contient beaucoup plus (je ne suis pas sûr des extraits de code spécifiques à l’interface graphique, je veux dire strictement spécifiques au filetage). Je serais heureux d'entendre ce que la communauté pense de ce travail parce que je lis celui-ci. Pour l’instant, j’avais l’air très chouette (pour montrer les méthodes et types spécifiques à .NET pour les threads). En outre, il couvre .NET 2.0 (et non l'ancienne version 1.1) ce que j'apprécie vraiment.

0
IgorK

Je vous conseillerais de consulter Rich Power Library de Jeff Richter, et plus particulièrement IAsyncEnumerator. Regardez la vidéo sur le blog de Charlie Calvert où Richter le passe pour un bon aperçu.

Ne vous fiez pas à son nom, car cela simplifie la codification des tâches de programmation asynchrone.

0
Robert Paulson