1.Thread
// one thread
Thread thread = new ThreadStart(functiion);
thread.Start();
// thread.join
Thread ThreadA = new Thread(delegate()
{
//do something
});
Thread ThreadB = new Thread(delegate()
{
//do something;
ThreadA.Join();
//do another thing
});
//启动线程
ThreadA.Start();
ThreadB.Start();
//一开始,两个线程相互交替运行,当线程B运行到线程A的join时,会先让线程A执行完,然后线程B再继续执行。你可以理解为超车,一开始两者互不相让,当join时,线程A超车了线程B
2.Threadpool
由于线程的创建和销毁需要耗费一定的开销,过多的使用线程会造成内存资源的浪费,出于对性能的考虑,于是引入了线程池的概念。线程池维护一个请求队列,线程池的代码从队列提取任务,然后委派给线程池的一个线程执行,线程执行完不会被立即销毁,这样既可以在后台执行任务,又可以减少线程创建和销毁所带来的开销。
如果一个线程的时间非常长,就没必要用线程池了),况且我们还不能控制线程池中线程的开始、挂起、和中止。
ThreadPool.QueueUserWorkItem(function,parameter);
3.Backgroundworker
System.ComponentModel.BackgroundWorker bgWorker = new System.ComponentModel.BackgroundWorker(); public MainWindow() { InitializeComponent(); this.bgWorker.DoWork += bgWorker_DoWork; // 不可以注册多次 } private void bgWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { ShowThreadId(this.lbBgWorker); AsyncProgressBar(this.proBgWorker); }
private void btBgWorker_Click(object sender, RoutedEventArgs e) { if (this.bgWorker.IsBusy) return; this.bgWorker.RunWorkerAsync(); // bgWorker 可以在线程函数中直接调用 ReportProgress 当然要先注册事件响应函数 // this.bgWorker.ProgressChanged += bgWorker_ProgressChanged; // bgWorker.ReportProgress }
BackgroundWorker 内部使用 Threadpool 实现,实现了 IComponentModel 接口,封装了进度报告等 UI 相关事件,方便 UI 相关编程。
4.Task
// one task var task = new Task(() =>{ // do something }); task.Start(); // task one by one var task = new Task(() =>{ // do something }); Task task2 = task.ContinueWith(()=>{ // do something }); task.Start(); // many tasks var tasks = new Task[PackCount]; //多线程任务 for (int index = 0; index < PackCount; index++) { int Threadindex = index; var task = new Task(() => { // do something } }); tasks[Threadindex] = task; task.Start(); } Task.WaitAll(tasks); //等待所有线程完成 //Task.WaitAny(tasks); //等待一个线程完成继续执行主程序 //Task.Factory Task.Factory.StartNew(()=>{ // do something });
5.异步委托delegate:Invoke、BeginInvoke、DynamicInvoke
此处主要说明的是delegate下的各种Invoke
1. Invoke (委托方法执行是在调用处的同一个线程中)
2.BeginInvoke(它从线程池中抓取一个空闲线程,来委托执行方法)delegate void MyDelegate(); MyDelegate del = new MyDelegate(Function); del .Invoke(); //使用到委托的invoke方法
A情况:使用IAsyncResult.IsCompleted判断子线程是否执行完毕:
B情况:使用IAsyncResult.AsyncWaitHandle.WaitOne(timeout)判断子线程是否执行完毕delegate T MyDelegate(); MyDelegate del = new MyDelegate(Function); IAsyncResult result = del.BeginInvoke(parameter,null,null); //if the branch thread is not completed while(!result.IsCompleted) { // the main thread do another thing } T data = del.EndInvoke(result); // var data is the result of Function with parameter
C情况:使用WaitHandle.WaitAll(WaitHandle[],timeout)判断子线程是否执行完毕delegate T MyDelegate(); MyDelegate del = new MyDelegate(Function); IAsyncResult result = del.BeginInvoke(parameter,null,null); //if the branch thread is not completed while(!result.AsyncWaitHandle.WaitOne(int timeout)) { // the main thread do another thing } T data = del.EndInvoke(result); // var data is the result of Function with parameter
D情况:使用轮询方式来检测异步方法的状态非常麻烦,而且效率不高,为此需要使用回调函数。主线程可以安心做自己的事,而异步线程完成操作后执行回调函数即可。回调函数依然是在异步线程上,而非主线程上。delegate T MyDelegate(); MyDelegate del = new MyDelegate(Function); IAsyncResult result = del.BeginInvoke(parameter,null,null); WaitHandle[] waitHandleList = new WaitHandle[] { result.AsyncWaitHandle,........ }; while (!WaitHandle.WaitAll(waitHandleList,int timeout)) { // the main thread do another thing } T data = del.EndInvoke(result); // var data is the result of Function with parameter
3. DynamicInvoke:delegate T MyDelegate(); MyDelegate del = new MyDelegate(Function); IAsyncResult result = del.BeginInvoke(parameter,new AsyncCallback(callbackFunction),object); ....MainThread do somethng... static void callbackFunction(IAsyncResult result) { AsyncResult _result = (AsyncResult )result; MyDelegate del = (MyDelegate)_result.AsyncDelegate; T data = del.EndInvoke(_result); T1 objectReciever = (T1)result.AsyncResult; //object=result.AsyncResult }
与Delegate.Invoke类似,同步,且同线程,唯一不同的是,是采用后期绑定的方式来调用委托方法,所以时间代价较大。
工作实例:在WPF中出现一种异常:“调用线程无法访问此对象,因为另一个线程拥有该对象。”
情况A:假设发生该异常的代码是在xaml.cs文件中,那么Dispatcher.Invoke已经够用了。
情况B: 假设发生该异常的代码是在.cs文件中,那么在Stack Overflow上有一招:
private void RaiseEventOnUIThread(Delegate theEvent, object[] args) { foreach (Delegate d in theEvent.GetInvocationList()) { ISynchronizeInvoke syncer = d.Target as ISynchronizeInvoke; if (syncer == null) //静态函数为null { d.DynamicInvoke(args); } else { syncer.BeginInvoke(d, args); //在创建了此对象的线程上异步执行委托 } } }