本文通过介绍C#多线程的用法(基础玩法),附加介绍一下WinForm里边跨线程访问UI的方法

如图,就是这么一个简单的界面,每个按钮下面一个方法,分别设置文本框里边的内容,那么,开始吧!

先介绍一下WinForm的线程模型:WinForm 是通过调用Windows API 的GetMessage Or PeekMeeage来处理其他线程发送过来的消息,这些消息存储在系统的一个消息队列中,创建主界面的线程就是主线程(UI线程),UI线程负责消费该消息队列中的消息。

WinForm框架中有一个ISynchronizeInvoke接口,所有的UI元素都继承自该接口,接口中的InvokeRequired属性表示了当前线程是否是创建它的线程,接口中的BeginInvoke or Invoke 负责将消息发送到消息队列,这样UI线程就能够正确的访问它了。

那么,首先看代码片段一:里边就实现了将设置文本框内容的消息发送到了消息队列

private void SetMessage(string message)
{
if (this.txtMsg.InvokeRequired)
{
//BeginInvoke or Invoke 负责将消息发送到消息队列
this.txtMsg.BeginInvoke(new Action<string>((msg) =>
{
this.txtMsg.Text = msg;
}), message);
}
else
{
this.txtMsg.Text = message;
} }

代码片段二Thread:Thread可能是用的最多的了,也是最早的框架里边就有的。这种写法很简单,也很方便,需要提一下的就是IsBackground属性,IsBackground=true表示为后台线程,应用程序退出,哪怕任务没有执行完,也会退出;IsBackground=false表示为前台线程,默认为false,应用程序退出,只要任务还没有执行完,进程就不会结束。

private void btnThread_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
SetMessage("Thread 跨线程访问UI");
});
//IsBackground=true表示为后台线程 应用程序退出 哪怕任务没有执行完 也会退出
//IsBackground=false表示为后台线程 默认为false 应用程序退出 只要任务还没有执行完 进程就不会结束
thread.IsBackground = true;
thread.Start();
}

代码片段三ThreadPool:ThreadPool是微软为了避免开发人员,无节制的使用线程,而提供的一个线程管理类

private void btnThreadPool_Click(object sender, EventArgs e)
{
//线程池 是微软为了避免开发人员 无节制的使用线程 而提供的一个线程管理类
ThreadPool.QueueUserWorkItem((obj) =>
{
SetMessage("ThreadPool 跨线程访问UI");
}, null);
}

代码片段四Task:Task有很多的优势,也是后面高版本才推出来的,推荐使用。Task与Thread的区别就是:Task使用的是线程池中的线程,Task较之线程池的优势是:

1.Task支持取消,完成,失败通知等交互性操作

2.Task支持线程执行的先后次序

private void btnTask_Click(object sender, EventArgs e)
{
/* Task与Thread的区别就是:Task使用的是线程池中的线程
* Task较之线程池的优势是:
* 1.Task支持取消,完成,失败通知等交互性操作
* 2.Task支持线程执行的先后次序*/
Task.Factory.StartNew(() =>
{
SetMessage("Task 跨线程访问UI");
}); Task task = new Task(()=> {
SetMessage("Task 跨线程访问UI");
});
task.Start();
}

代码片段五BackgroundWorker:BackgroundWorker内部是通过线程池实现的,通过事件提供了跨线程访问UI的能力,这个做CS开发,是用的最多的,说白了,太好用。

//BackgroundWorker 内部是通过线程池实现的
//BackgroundWorker 通过事件提供了跨线程访问UI的能力
BackgroundWorker _bgw = new BackgroundWorker(); private void btnBackgroundWorker_Click(object sender, EventArgs e)
{
_bgw.WorkerReportsProgress = true;
_bgw.WorkerSupportsCancellation = true;
_bgw.DoWork += _bgw_DoWork; ;
_bgw.ProgressChanged += _bgw_ProgressChanged;
_bgw.RunWorkerCompleted += _bgw_RunWorkerCompleted; if (!_bgw.IsBusy)
{
_bgw.RunWorkerAsync();
}
} private void _bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.txtMsg.Text = "BackgroundWorker 跨线程访问UI";//注意这里是直接访问UI
} private void _bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.txtMsg.Text = e.UserState.ToString();//注意这里是直接访问UI
} private void _bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
_bgw.ReportProgress(i, $"{i}秒");
}
}

代码片段六SynchronizationContext:SynchronizationContext同步上下文在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯,这个在跨线程一次性要更新很多的UI控件的时候,非常的适用。

//SynchronizationContext 在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯
SynchronizationContext _syncContext; private void btnSynchronizationContext_Click(object sender, EventArgs e)
{
_syncContext = SynchronizationContext.Current;
Thread thread = new Thread(() =>
{
if (_syncContext != null)
{
SendOrPostCallback callBack = (obj) =>
{
//在某个子线程里 一次性要更新很多UI控件的时候 用这个方法 很nice
this.txtMsg.Text = "SynchronizationContext 跨线程访问UI";
};
_syncContext.Post(callBack, null);//异步
//_syncContext.Send(callBack, null);//同步
}
});
thread.IsBackground = true;
thread.Start();
}

合并之后的代码为:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms; namespace ThreadChapter
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void btnThread_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
SetMessage("Thread 跨线程访问UI");
});
//IsBackground=true表示为后台线程 应用程序退出 哪怕任务没有执行完 也会退出
//IsBackground=false表示为后台线程 默认为false 应用程序退出 只要任务还没有执行完 进程就不会结束
thread.IsBackground = true;
thread.Start();
} /*
* WinForm 是通过调用Window API 的GetMessage Or PeekMeeage来处理其他线程发送过来的消息,
* 这些消息存储在系统的一个消息队列中,创建主界面的线程就是主线程(UI线程),UI线程负责处理该消息队列
*/ private void SetMessage(string message)
{
if (this.txtMsg.InvokeRequired)
{
//BeginInvoke or Invoke 负责将消息发送到消息队列
this.txtMsg.BeginInvoke(new Action<string>((msg) =>
{
this.txtMsg.Text = msg;
}), message);
}
else
{
this.txtMsg.Text = message;
} } private void btnThreadPool_Click(object sender, EventArgs e)
{
//线程池 是微软为了避免开发人员 无节制的使用线程 而提供的一个线程管理类
ThreadPool.QueueUserWorkItem((obj) =>
{
SetMessage("ThreadPool 跨线程访问UI");
}, null);
} private void btnTask_Click(object sender, EventArgs e)
{
/* Task与Thread的区别就是:Task使用的是线程池中的线程
* Task较之线程池的优势是:
* 1.Task支持取消,完成,失败通知等交互性操作
* 2.Task支持线程执行的先后次序*/
Task.Factory.StartNew(() =>
{
SetMessage("Task 跨线程访问UI");
});
} //BackgroundWorker 内部是通过线程池实现的
//BackgroundWorker 通过事件提供了跨线程访问UI的能力
BackgroundWorker _bgw = new BackgroundWorker(); private void btnBackgroundWorker_Click(object sender, EventArgs e)
{
_bgw.WorkerReportsProgress = true;
_bgw.WorkerSupportsCancellation = true;
_bgw.DoWork += _bgw_DoWork; ;
_bgw.ProgressChanged += _bgw_ProgressChanged;
_bgw.RunWorkerCompleted += _bgw_RunWorkerCompleted; if (!_bgw.IsBusy)
{
_bgw.RunWorkerAsync();
}
} private void _bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.txtMsg.Text = "BackgroundWorker 跨线程访问UI";//注意这里是直接访问UI
} private void _bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.txtMsg.Text = e.UserState.ToString();//注意这里是直接访问UI
} private void _bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
_bgw.ReportProgress(i, $"{i}秒");
}
} //SynchronizationContext 在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯
SynchronizationContext _syncContext; private void btnSynchronizationContext_Click(object sender, EventArgs e)
{
_syncContext = SynchronizationContext.Current;
Thread thread = new Thread(() =>
{
if (_syncContext != null)
{
SendOrPostCallback callBack = (obj) =>
{
//在某个子线程里 一次性要更新很多UI控件的时候 用这个方法 很nice
this.txtMsg.Text = "SynchronizationContext 跨线程访问UI";
};
_syncContext.Post(callBack, null);//异步
//_syncContext.Send(callBack, null);//同步
}
});
thread.IsBackground = true;
thread.Start();
}
}
}

最新文章

  1. 微软职位内部推荐-Senior Software Engineer_Azure
  2. 创建Spring容器
  3. 【js类库AngularJs】web前端的mvc框架angularjs之hello world
  4. POJ 1577 Falling Leaves
  5. Codeforces Round #361 (Div. 2)
  6. L001-oldboy-mysql-dba-lesson01
  7. unity3d中脚本生命周期(MonoBehaviour lifecycle)
  8. Delphi使用XmlHttp获取时间
  9. Entity Framework学习笔记
  10. With our powers combined! xgboost and pipelearner
  11. Unity3D文件读取
  12. Dapper入门教程(一)——Dapper介绍
  13. Grafana简单使用
  14. 我的第一个MyBatis
  15. webapi 下载Ftp文件并返回流到浏览器完成文件下载
  16. 【数据库】MySQL的左连接、右连接和全连接的实现
  17. Codeforces 961E - Tufurama
  18. TL认证和运作经典案例评选
  19. 在CentOS中安装与配置SVN的方法
  20. 自己动手做AI:Google AIY开发工具包解析

热门文章

  1. noip模拟赛 卖书
  2. 2018/3/4 Activiti教程之流程部署篇(与Springboot整合版)二
  3. CLR GC
  4. HDU——2647 Reward
  5. Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter的使用
  6. u启动为苹果笔记本重装win7系统教程
  7. excel 合并 单元格内容
  8. 【转】基于Linux下的TCP编程
  9. owncloud
  10. Outlook2010 没有Exchange Server,怎么自动回复邮件?