点击“测试”,创建一个线程,从0循环到10000给文本框赋值,代码如下:
private void Button1_Click(object sender, EventArgs e)
//创建一个线程去执行这个方法:创建的线程默认是前台线程
Thread thread = new Thread(new ThreadStart(Test));
//将线程设置为后台线程
thread.IsBackground = true;
//Start方法标记这个线程就绪了,可以随时被执行,具体什么时候行这个线程,由CPU决定
thread.Start();
private void Test()
for (int i = 0; i< 10000; i++)
this.textBox1.Text = i.ToString();
运行结果:
产生错误的原因:textBox1是由主线程创建的,thread线程是另外创建的一个线程,在.NET上执行的是托管代码,C#强制要求这些代码必须是线程安全的,即不允许跨线程访问Windows窗体的控件。
2. 解决方案: 使用回调函数
什么叫回调函数呢?比如,你调用了一个函数,那么就叫调用,但是如果你在调用一个函数的时候,还需要把一个函数提供该函数,让这个函数来调用你的函数,那么你提供的这个函数就被称为回调函数(callback)C#的方法回调函数(机制),也是建立在委托基础上的。
使用方法回调,实现给文本框赋值:
private delegate void setTextValueCallBack(int value);
//声明回调
private setTextValueCallBack setCallBack;
private void Button1_Click(object sender, EventArgs e)
//实例化回调
setCallBack = SetValue;
//创建一个线程去执行这个方法:创建的线程默认是前台线程
Thread thread = new Thread(Test);
//Start方法标记这个线程就绪了,可以随时被执行,具体什么时执这个线程,由CPU决定
//将线程设置为后台线程
thread.IsBackground = true;
thread.Start();
private void Test()
for (int i = 0; i < 10000; i++)
//textBox1.Invoke拥有此控件的基础窗口句柄的线程上执行指定的委托。
//使用回调。主线程执行setCallBack委托
//也就是说,Invoke()是一个方法,这方法执行的是委托,并且是在一个固定的线程上执行的。
//什么样的 线程? 拥有此控件的基础窗口句柄的线程。
// 这个“拥有此控件的基础窗口句柄的线程”实际上就是 “主线程”,
//窗体加载时 程序会创建一个 “主线程”。
if (textBox1.InvokeRequired)//如果为跨线程访问
textBox1.Invoke(setCallBack, i);//i就是传给回调函数的值
补充:Control.InvokeRequired
这个属性来进行判断是否是调用方对该控件进行调用控件,如果不是创建这个控件的线程来调用它,则返回true(即是跨线程访问就为true),否则返回False。
以上代码可以简化,只需要下面2个方法即可,利用内置委托Action,传入一个参数,内置委托即是回调函数,i是传给委托/回调函数的参数:
private void Test()
for (int i = 0; i < 10000; i++)
if (textBox1.InvokeRequired)
textBox1.Invoke(new Action<int>(n => { this.textBox1.Text = n.ToString(); }),i);
private void Button1_Click(object sender, EventArgs e)
Thread th = new Thread(Test);
th.IsBackground = true;
th.Start();
从以上回调实现的一般过程可知:C#的回调机制,实质上是委托的一种应用。
本文根据徐照兴教授讲义编写,有些改动。
1. 跨线程访问出现错误例子:点击“测试”,创建一个线程,从0循环到10000给文本框赋值,代码如下:private void Button1_Click(object sender, EventArgs e){ //创建一个线程去执行这个方法:创建的线程默认是前台线程 Thread thread = new Thread(new ThreadStart(Test));...
一般在上位机界面的开发中,通常都需要在后台线程计算处理数据。然后在上位机显示,对于多任务处理,通常都是采用多线程的方法,这就要求必须采用线程间的通信。最简单的就是全局变量,等同是在共享数据,但这并不是最安全可靠的,同时对系统的开销大,还存在资源争夺的问题。无论采用何种框架,都无法直接在子工作线程中,直接对主线程(UI)进行数据更新。
常用分几种C#UI开发下的使用方法:
通过UI线程的SynchronizationContext的Post/Send方法更新
通过UI控件的Invoke/BeginInv
在进行Winform程序开发需要进行大量的数据的读写操作的时候,往往会需要一定的时间,然在这个时间段里面,界面ui得不到更新,导致在用户看来界面处于假死的状态,造成了不好的用户体验。所以在大量数据操作的应用上,需要使用多线程来处理这种情况。在c#中使用多线程很方便只需要使用System.Threading.Thread的一个实例的Start方法就行了,但是如何实现多线程之间的交互就不是那么简单。本文实现了用子线程去处理数据,并实时更新主线程的ui状态了。下面就开始一步步的去实现异步线程更新ui的demo程序吧。
写入一定量的数据到文本文件中,同时需要在主界面中反应出写入数据的
本文参考博客
C#多线程 https://www.cnblogs.com/dotnet261010/p/6159984.html
C# 线程与进程 https://www.cnblogs.com/craft0625/p/7496682.html
C# 跨线程调用控件https://www.cnblogs.com/TankXiao/p/3348292.html
对于c#中的线程和进程,这两篇文章讲的相当到位了,本文只是为了学习做的摘要。
线程是什么?
C# Winform跨线程更新UI控件的方法
1、通过SynchronizationContext的Post/Send方法
2、通过Invoke/BeginInvoke方法
3、通过设置窗体属性,取消线程安全检查来避免"线程间操作无效异常"
http://blog.csdn.net/yangyuankp/article/details/7672370
C#利用委托跨线程更新UI数据
在使用C#的过程中,难免会用到多线程,而用多线程之后,线程如何与界面交互则是一个非常头疼的问题。其实不仅仅是界面,一般情况下,我们往往需要获得线程的一些信息来确定线程的状态。比较好的方式是用委托实现,看例子:
注:本例利用委托和跨线程访问技术