我如何运行一个简单的代码在一个新的线程?

我有一些代码,我需要运行在不同的线程,而不是GUI,因为它目前导致窗体冻结,而代码运行(10秒左右)。

假设我以前从未创建过一个新线程;有什么简单/基本的例子,如何做到这一点在c#和使用。net Framework 2.0或更高版本?

492817 次浏览

尝试使用BackgroundWorker类。您为它指定要运行的内容,并在工作完成时通知它。在我链接到的MSDN页面上有一个例子。

又快又脏,但很管用:

用于顶部:

using System.Threading;

简单的代码:

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


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

我只是将其放入一个新的控制台应用程序中作为示例

ThreadPool。QueueUserWorkItem对于简单的东西来说是非常理想的。唯一需要注意的是从另一个线程访问控件。

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

将该代码放入一个函数中(不能与GUI在同一个线程上执行的代码),并执行以下代码来触发该代码的执行。

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

在线程对象上调用start函数将导致在新线程中执行函数调用。

另一种选择,使用委托和线程池…

假设'GetEnergyUsage'是一个方法,它接受一个DateTime和另一个DateTime作为输入参数,并返回一个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);

如何:使用后台线程搜索文件

您必须非常小心从其他线程访问特定于GUI的东西(这对许多GUI工具包来说很常见)。如果你想在GUI中从处理线程检查这个答案中更新一些东西,我认为这对WinForms很有用。对于WPF,请参阅(它展示了如何在UpdateProgress()方法中触摸组件,因此它将从其他线程工作,但实际上我不喜欢它在通过Dispathcer, 看到和搜索CheckAccess之前不做CheckAccess())

正在寻找。net关于线程的特定书籍,并找到这一个(免费下载)。有关它的更多细节,请参阅http://www.albahari.com/threading/

我相信你会发现你需要启动执行作为新线程在前20页,它有更多(不确定GUI特定片段,我的意思是严格特定于线程)。很高兴听到社区对这项工作的看法,因为我正在读这个。对我来说,现在看起来非常整洁(用于显示。net特定的线程方法和类型)。此外,它还涵盖了我真正欣赏的。net 2.0(而不是古老的1.1)。

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

在Code Project网站上有一个很好的异步方法文章,它描述了各种方法并提供了示例代码。

注意本文是在。net引入异步/等待模式和任务并行库模式之前编写的。

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

但如果你阻止了,发出任何c调用又有什么意义呢?您也可以只使用同步调用。一个更好的选择是不阻塞,并传入一个lambda来进行清理:

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

有一件事要记住,你必须调用EndInvoke。很多人忘记了这一点,最终泄露了WaitHandle,因为大多数异步实现在EndInvoke中释放了WaitHandle。

如果你打算使用原始线程对象,那么你需要将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类。

我建议看看Jeff Richter的电源线程库,特别是IAsyncEnumerator。看看查理·卡尔弗特的博客上的视频,Richter在那里对它进行了很好的概述。

不要被这个名字吓倒,因为它使异步编程任务更容易编码。

BackgroundWorker似乎是你的最佳选择。

下面是我的最小示例。在你点击按钮后,后台工作人员将开始在后台线程工作,并同时报告其进度。它也将在工作完成后报告。

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#的匿名方法 简单但你总是可以拉 . .
  • 更新GUI是安全的 ProgressChangedRunWorkerCompleted处理程序。 然而,从DoWork更新GUI 将会导致 李InvalidOperationException。< / >

如果你想得到一个值:

var someValue;


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


thread.Start();


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

开始阅读的好地方是乔Albahari

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

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

这是另一种选择:

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

这里如何使用线程和一个progressBar,这只是为了理解线程是如何工作的,在表单中有三个progressBar和4个按钮:

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