Como faço para executar um simples pedaço de código em um novo tópico?

Eu tenho um pouco de código que eu preciso executar em um thread diferente do GUI porque ele atualmente faz com que o formulário para congelar enquanto o código corre (10 segundos ou assim).

Assume que nunca criei um novo tópico antes; Qual é um exemplo simples / básico de como fazer isto em C# e usar o Framework. NET 2.0 ou mais tarde?

Author: p.campbell, 2008-12-12

15 answers

O bom lugar para começar a ler é o Joe Albahari.

Se quiser criar o seu próprio tópico, isto é o mais simples possível:

using System.Threading;
new Thread(() => 
{
    Thread.CurrentThread.IsBackground = true; 
    /* run your code here */ 
    Console.WriteLine("Hello, world"); 
}).Start();
 267
Author: Ed Power, 2017-08-11 13:40:52

BackgroundWorker parece ser a melhor escolha para ti.

Eis o meu exemplo mínimo. Depois de clicar no botão o trabalhador de fundo vai começar a trabalhar em linha de fundo e também relatar o seu progresso simultaneamente. O relatório será também apresentado após a conclusão dos trabalhos.
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();
    }

Nota:

    Coloquei tudo num único método. usando o método anónimo de C#para simplicidade mas você pode sempre puxar são métodos diferentes.
  • é seguro actualizar a interface gráfica no ProgressChanged ou RunWorkerCompleted manipuladores. No entanto, a actualização da interface gráfica de DoWork causará InvalidOperationException.
 184
Author: Gant, 2014-08-21 16:49:54

The ThreadPool.O QueueUserWorkItem é bastante ideal para algo simples. A única advertência é aceder a um controlo do outro fio.

System.Threading.ThreadPool.QueueUserWorkItem(delegate {
    DoSomethingThatDoesntInvolveAControl();
}, null);
 96
Author: Mark Brackett, 2008-12-12 16:59:50
Rápido e sujo, mas vai funcionar.

Usando no topo:

using System.Threading;

Código simples:

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

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

Acabei de lançar isto numa nova aplicação de consola para um exmaple

 68
Author: FallenAvatar, 2008-12-12 16:59:39

Aqui está outra opção:

Task.Run(()=>{
//Here is a new thread
});
 50
Author: Spongebob Comrade, 2015-08-03 02:25:17

Tente usar a classeBackgroundWorker . Você dá-lhe delegados para o que correr, e para ser notificado quando o trabalho tiver terminado. Há um exemplo na página MSDN a que liguei.

 38
Author: Andy, 2008-12-12 16:56:54

Se quiser obter um valor:

var someValue;

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

thread.Start();

while (thread.IsAlive)
  Application.DoEvents();
 14
Author: sth, 2009-08-07 03:28:56

Coloque esse código numa função (o código que não pode ser executado no mesmo tópico que a interface gráfica), e para activar a execução desse código coloque o seguinte.

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

Se invocar a função inicial no objecto do tópico, irá causar a execução da sua chamada de função num novo tópico.

 6
Author: Redbaron, 2008-12-12 17:00:47

Aqui, como usar os tópicos com uma barra de progresso, é apenas para perceber como os tópicos funcionam, na forma de três barras de progresso e 4 Botão:

 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
Author: Ammar Alyasry, 2016-10-15 14:34:42
// 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 o teu código (acima) não está correcto. Você não precisa girar esperar para a conclusão. O EndInvoke bloqueia até o sinal do WaitHandle.

Se quiser bloquear até à conclusão, basta que

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

Ou em alternativa

ar.AsyncWaitHandle.WaitOne();

Mas qual é o objectivo de emitir chamadas se bloquear? Mais vale usares uma chamada sincronizada. Uma melhor aposta seria não bloquear e passar em um lambda para limpeza:

nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);
Uma coisa para manter a mente é que você deve chamar EndInvoke. Muitas pessoas se esquecem disso e acabam vazando o WaitHandle como a maioria das implementações async liberam o waithandle em EndInvoke.
 3
Author: Matt Davison, 2018-08-01 06:45:11

Se você vai usar o objecto de Thread raw, então você precisa definir o IsBackground como true no mínimo e você também deve definir o modelo de apartamento de Thread (provavelmente 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()
}
Eu recomendaria a aula de BackgroundWorker se precisares de interacção UI.
 2
Author: user50612, 2018-08-01 06:13:25
Outra opção, que usa delegados e o grupo de roscas...

Assumindo que 'GetEnergyUsage' é um método que toma uma DateTime e outra DateTime como argumentos de entrada, e retorna um Int...

// 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
Author: Charles Bretana, 2008-12-12 17:14:07

Existem muitas maneiras de executar threads separados em. Net, cada um tem comportamentos diferentes. Precisa de continuar a correr o tópico depois da interface gráfica sair? Você precisa passar informações entre o fio e a interface gráfica? O tópico precisa de actualizar a interface gráfica? O tópico deve fazer uma tarefa então sair, ou deve continuar a correr? As respostas a estas perguntas dir-lhe-ão qual o método a utilizar.

Existe um bom Método async artigo no site do projeto de código que descreve os vários métodos e fornece o código da amostra.

Note que este artigo foi escrito antes de o padrão async/await e Biblioteca paralela de Tarefas terem sido introduzidos na. NET.

 1
Author: Dour High Arch, 2018-03-26 16:54:21

Como: usar um tópico de fundo para procurar por Ficheiros

Você tem que ser muito cuidadoso com o acesso de outros tópicos a coisas específicas da interface (é comum para muitos kits de ferramentas da interface gráfica). Se quiser actualizar alguma coisa na interface gráfica a partir do processamento da verificação do tópico , esta resposta que eu ache útil para WinForms. Para WPF veja isto (mostra como tocar o componente no método UpdateProgress() para que funcione a partir de outros tópicos, mas na verdade não gosto que não esteja a fazer {[[0]} antes de fazer BeginInvoke através de Dispathcer, ver e procurar por CheckAccess nele

Estava à procura de um livro específico da.NET sobre roscagem e encontrou Este (disponível gratuitamente). Ver http://www.albahari.com/threading para mais detalhes.

Eu acredito que você vai encontrar o que você precisa para lançar a execução como novo tópico nas primeiras 20 páginas e que tem muito mais (Não tenho certeza sobre os excertos específicos GUI quero dizer estritamente específico para a threading). Ficaria feliz em saber o que a comunidade pensa deste trabalho porque eu estou a ler este. Por agora parecia muito limpo para mim (para mostrar métodos específicos.NET e tipos para threading). Também cobre. NET 2.0 (e não antigo 1.1) O que eu realmente aprecio.

 0
Author: IgorK, 2017-05-23 11:55:01
Eu recomendaria ver a biblioteca de Power Threading de Jeff Richter e, especificamente, o Iasyncenumerador. Dê uma olhada no vídeo no blogue de Charlie Calvert onde Richter passa por cima dele para uma boa visão geral.

Não se esqueça do nome porque torna as tarefas de programação assíncronas mais fáceis de codificar.

 0
Author: Robert Paulson, 2009-01-27 02:22:47