Como executo um pouco de código simples em um novo segmento?

Eu tenho um pouco de código que eu preciso para executar em um segmento diferente que o GUI, pois atualmente faz com que o formulário congelar enquanto o código é executado (10 segundos ou mais).

Suponha que eu nunca tenha criado um novo tópico antes; O que é um exemplo simples / básico de como fazer isso em c # e usando o .NET Framework 2.0 ou posterior?

   

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

Se você quer criar seu próprio tópico, isso é o mais simples possível:

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

BackgroundWorker parece ser a melhor escolha para você.

Aqui está o meu exemplo mínimo. Depois de clicar no botão, o trabalhador em segundo plano começará a trabalhar no encadeamento em segundo plano e também relatará seu progresso simultaneamente. Ele também informará após o término do trabalho.

 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:

  • Eu coloquei tudo em um único método usando o método anônimo do C # para simplificar, mas você sempre pode extraí-los para methods diferentes.
  • É seguro atualizar a GUI nos manipuladores ProgressChanged ou RunWorkerCompleted . No entanto, atualizar a GUI do DoWork causará InvalidOperationException .

O ThreadPool.QueueUserWorkItem é bastante ideal para algo simples. A única ressalva é acessar um controle do outro segmento.

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

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 } 

Eu só joguei isso em um novo aplicativo de console para uma exmaple

Aqui está outra opção:

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

Tente usar a class BackgroundWorker . Você dá delegates para o que executar e para ser notificado quando o trabalho terminar. Há um exemplo na página do MSDN à qual eu me vinculei.

Se você 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(); 

Coloque esse código em uma function (o código que não pode ser executado no mesmo thread que a GUI) e para acionar a execução desse código, coloque o seguinte.

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

Chamar a function de início no object de thread fará com que a execução de sua chamada de function em um novo segmento.

Aqui, como podemos usar threads com um progressBar, é apenas para entender como os threads funcionam, no formulário há três progressBar e 4 button:

  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(); } } 
 // 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 seu código (acima) não está correto. Você não precisa girar esperar pela conclusão. EndInvoke bloqueará até que o WaitHandle seja sinalizado.

Se você quiser bloquear até a conclusão você simplesmente precisa

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

ou alternativamente

 ar.AsyncWaitHandle.WaitOne(); 

Mas qual é o sentido de emitir chamadas anyc se você bloquear? Você também pode usar uma chamada síncrona. Uma aposta melhor seria não bloquear e passar um lambda para limpeza:

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

Uma coisa a ter em mente é que você deve ligar para o EndInvoke. Muitas pessoas esquecem isso e acabam vazando o WaitHandle, já que a maioria das implementações assíncronas liberam o waithandle no EndInvoke.

Se você for usar o object Thread raw, precisará definir IsBackground como true no mínimo e também definir o modelo Threading Apartment (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 class BackgroundWorker se você precisar de interação com a interface do usuário.

outra opção, que usa delegates e o pool de threads …

Assumindo ‘GetEnergyUsage’ é um método que leva um DateTime e outro DateTime como argumentos de input, e …

 // 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); 

Há muitas maneiras de executar segmentos separados no .net, cada um tem diferentes comportamentos. Você precisa continuar executando o thread após a GUI sair? Você precisa passar informações entre o thread e a GUI? O encadeamento precisa atualizar a GUI? O thread deve fazer uma tarefa e depois sair ou continuar funcionando? As respostas a estas perguntas lhe dirão qual método usar.

Há um bom artigo de método asynchronous no site do Code Project que descreve os vários methods e fornece código de amostra.

Observe que este artigo foi escrito antes que o padrão async / await e a Biblioteca paralela da tarefa fossem introduzidos no .NET.

How to: Use um thread em segundo plano para procurar por arquivos

Você tem que ter muito cuidado com o access de outros tópicos para coisas específicas da GUI (é comum para muitos toolkits GUI). Se você quiser atualizar algo na GUI do thread de processamento, verifique esta resposta que eu acho que é útil para WinForms. Para o WPF, veja isso (ele mostra como tocar o componente no método UpdateProgress () para que funcione de outros threads, mas na verdade eu não gosto que ele não esteja fazendo CheckAccess() antes de fazer BeginInvoke através do Dispathcer, veja e pesquise o CheckAccess em isto)

Estava procurando .NET livro específico sobre segmentação e encontrei este (livre para download). Veja http://www.albahari.com/threading/ para mais detalhes sobre o assunto.

Eu acredito que você vai encontrar o que você precisa para iniciar a execução como novo thread nas primeiras 20 páginas e tem muito mais (não tenho certeza sobre trechos específicos da GUI, quero dizer estritamente específico para segmentação). Ficaria feliz em ouvir o que a comunidade pensa sobre este trabalho porque eu estou lendo este aqui. Por enquanto parecia muito legal para mim (para mostrar methods específicos do .NET e tipos de segmentação). Também abrange .NET 2.0 (e não 1.1 antigo) o que eu realmente aprecio.

Eu recomendo olhar para a biblioteca Power Threading de Jeff Richter e especificamente o IAsyncEnumerator. Dê uma olhada no vídeo no blog de Charlie Calvert, onde Richter repassa para ter uma boa visão geral.

Não desanime pelo nome porque facilita a codificação de tarefas de programação assíncrona.