如何在新的线程中运行一段简单的代码?

我有一些代码需要在不同于GUI的线程中运行,因为它当前会导致表单在代码运行时冻结(10秒左右)。

假设我从来没有创build过一个新的线程; 什么是如何在C#中使用.NET Framework 2.0或更高版本的简单/基本示例?

开始阅读的好地方是Joe Albahari 。

如果你想创build自己的线程,这是很简单的:

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

BackgroundWorker似乎是您的最佳select。

这是我最小的例子。 当你点击button后,后台工作人员将开始在后台线程工作,并同时报告进度。 工作完成后也会报告。

 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(); } 

注意:

  • 为了简单起见,我使用C#的匿名方法将所有内容都放在一个单独的方法中,但是您总是可以将它们拖放到不同的方法中。
  • ProgressChangedRunWorkerCompleted处理程序中更新GUI是安全的。 但是,从DoWork更新GUI将导致InvalidOperationException

ThreadPool.QueueUserWorkItem对于简单的事情来说非常理想。 唯一的警告是从另一个线程访问控件。

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

快速和肮脏,但它会工作:

使用顶部:

 using System.Threading; 

简单的代码:

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

我只是把它扔进了一个新的控制台应用程序

这是另一个select:

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

尝试使用BackgroundWorker类。 你给它的代表什么运行,并在工作完成后得到通知。 在我链接到的MSDN页面上有一个例子。

如果你想得到一个价值:

 var someValue; Thread thread = new Thread(delegate() { //Do somthing and set your value someValue = "Hello World"; }); thread.Start(); while (thread.IsAlive) Application.DoEvents(); 

把这个代码放在一个函数中(不能在与GUI相同的线程上执行的代码),并触发代码的执行。

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

调用线程对象上的启动函数将导致在新线程中执行您的函数调用。

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

查找你的代码(上面)是不正确的。 你不需要等待完成。 EndInvoke将阻塞,直到WaitHandle被发送信号。

如果你想阻止,直到完成,你只需要

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

或者可选地

 ar.AsyncWaitHandle.WaitOne(); 

但是,如果你封锁,发出任何电话会有什么意义呢? 你可能只是使用同步调用。 更好的select是不阻塞并通过lambda进行清理:

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

有一点要记住,你必须调用EndInvoke。 很多人忘记了这一点,最终泄漏了WaitHandle,因为大多数asynchronous实现在EndInvoke中释放等待句柄。

如果你打算使用原始的Thread对象,那么你至less需要设置IsBackground为true,你也应该设置Threading Apartment模型(可能是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() } 

如果您需要UI交互,我会推荐BackgroundWorker类。

这里怎么可以使用带有progressBar的线程,它只是为了说明线程如何工作,在窗体中有三个progressBar和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(); } } 

另一个选项,使用委托和线程池…

假设“GetEnergyUsage”是一种方法,将DateTime和另一个DateTime作为input参数,并返回一个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); 

如何:使用后台线程来search文件

你必须非常小心地从其他线程访问GUI特定的东西(这是很多GUI工具包常见的)。 如果你想从处理线程更新GUI中的东西,请检查我认为对WinForms有用的答案 。 对于WPF来说,看看这个 (它显示了如何在UpdateProgress()方法中触摸组件,所以它可以从其他线程中工作,但实际上我不喜欢它在通过Dispathcer执行BeginInvoke之前没有执行CheckAccess() , 请参阅和searchCheckAccess它)

是看线程.NET特定的书,发现这一个 (免费下载)。 请参阅http://www.albahari.com/threading/了解更多细节。;

我相信你会发现什么你需要启动执行作为新的线程在前20页,并有更多的(不知道GUI特定的片段,我的意思是严格特定的线程)。 很高兴听到社区对这项工作的看法,因为我正在阅读这篇文章。 现在看起来很整洁(为了显示.NET特定的方法和线程types)。 它也涵盖了.NET 2.0(而不是古代1.1),我真的很感激。

在.Net中运行单独的线程有很多种方法,每个都有不同的行为。 GUI退出后,是否需要继续运行线程? 你需要在线程和GUI之间传递信息吗? 线程是否需要更新GUI? 线程应该执行一个任务然后退出,还是应该继续运行? 这些问题的答案会告诉你使用哪种方法。

代码项目网站上有一篇很好的asynchronous方法文章 ,介绍各种方法并提供示例代码。

我build议看看Jeff Richter的Power Threading Library ,特别是IAsyncEnumerator。 看一下查理·卡尔弗特(Charlie Calvert)的博客里的video,里奇特(Richter)为了一个很好的概览而去查看它。

不要被这个名字拖延,因为它使asynchronous编程任务更容易编码。