C# 跨线程访问及UI界面多线程更新方法

2.5 多线程并行编程 同时被 2 个专栏收录
9 篇文章 1 订阅
50 篇文章 0 订阅

1. 跨线程访问出现错误例子: 

 

  点击“测试”,创建一个线程,从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#的回调机制,实质上是委托的一种应用。

 

本文根据徐照兴教授讲义编写,有些改动。

  • 0
    点赞
  • 1
    评论
  • 12
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值