线程使用方法总结

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 (委托方法执行是在调用处的同一个线程中)

delegate void MyDelegate();

MyDelegate del = new MyDelegate(Function);
del .Invoke();     //使用到委托的invoke方法
2.BeginInvoke(它从线程池中抓取一个空闲线程,来委托执行方法)

A情况:使用IAsyncResult.IsCompleted判断子线程是否执行完毕:

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
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.AsyncWaitHandle.WaitOne(int timeout))  
{
    // 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);

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
D情况:使用轮询方式来检测异步方法的状态非常麻烦,而且效率不高,为此需要使用回调函数。主线程可以安心做自己的事,而异步线程完成操作后执行回调函数即可。回调函数依然是在异步线程上,而非主线程上。
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
}
3. DynamicInvoke:
与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); //在创建了此对象的线程上异步执行委托
            }
       }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值