【分享○教程】VB.NET创建和使用线程,以及跨线程的窗体控件调
vb2010吧
全部回复
仅看楼主
level 9
lipeiyi2006 楼主
[一楼喂熊]
2012年01月25日 04点01分 1
level 9
lipeiyi2006 楼主
2012年01月25日 04点01分 2
level 9
lipeiyi2006 楼主
VisualBasic作为易学易用的编程语言,为多少程序员所仰慕,VB历经多年的发展,从大家都熟知的VB6到如今的VB.NET,虽然这两个差别很大= =
本文主要讲述“线程”这么一个东西。
线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

2012年01月25日 05点01分 3
level 9
lipeiyi2006 楼主
为什么使用线程?
 我们一般编写的程序代码总是从main函数(控制台),Sub New()(类的构造函数),Load(窗体加载)开始执行的,从上往下,执行每一个调用,有明确的先后顺序,一个sub或者function完成之后,才进行下一个sub或者function。的确,这样程序的逻辑性很强,每个过程排队,依次来。
 但是,这样必然会在一定程度上降低应用程序的运行效率,如果某个过程代码很长,所需要的时间长,那么程序在执行这个过程的时候会出现“假死”,停止响应用户操作,知道过程全部执行完毕。
 关于“假死”:我们编写的Windows应用程序有一个UI线程,用于接收和响应用户界面的操作。而我们编写的代码一般都是基于这个线程的,位于单一线程中的代码也是从上往下依次进行,所以当UI线程中某一过程花费的时间很长时,界面不再响应,因为它很忙,这时就出现了长时间的停顿,也就是“假死”,而用户会认为这很卡。
 因此,如果我们在UI线程的基础上另开一个线程,让代码分支执行的话,就不会卡了。但同时,我们又不得不面临这样一个问题:万一线程执行的过程,和UI执行的过程有冲突怎么办?当你在非UI线程中调用UI线程中的某一个控件,设置它的某某属性,这时你会收到这样一条错误:
 →线程间操作无效: 从不是创建控件“xxx”的线程访问它。
怎么办啊? 别急,后文会有解释。

2012年01月25日 05点01分 4
level 9
lipeiyi2006 楼主
废话不多说,读者跟我一起来。
首先,我们来体验一下使用线程带来的好处和问题。
1.打开VS(我的是2010版本)。
2.创建Windows窗体应用程序随便弄个名。
3.在窗体上放两个控件,Label1个Button1,如图,其他属性默认:
我们想实现这样一个功能:
在Label1上面动态显示数字,从0~9000,我们希望看到数字的变化。

2012年01月25日 05点01分 5
level 9
lipeiyi2006 楼主
创建如下代码:
Public Class Form1
 Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    test()
 End Sub
 Private Sub test()
    For i = 0 To 9000
     Label1.Text = i.ToString
    Next
 End Sub
End Class
意思就是点击按钮,进入test过程中,通过For循环,依次显示数字,真是这样吗?运行试试...
不出我意料的话,最后直接显示的是9000,中间还卡了一下。
后面的0都不在了。。
那么,我们要显示动态变化又怎么办呢?
2012年01月25日 05点01分 6
给个Timer1控制他
2015年05月01日 12点05分
level 13
怎么办呢?
2012年01月25日 05点01分 7
level 9
lipeiyi2006 楼主
把上面的代码修改一下,使用线程。
Imports System.Threading ’导入命名空间
Public Class Form1
Dim t As Thread ’定义全局线程变量
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
t = New Thread(AddressOf test) ’创建线程,使它指向test过程,注意该过程不能带有参数
t.Start() ’启动线程
End Sub
Private Sub test()
For i = 0 To 9000
Label1.Text = i.ToString
Next
t.Abort()
End Sub
End Class
再次运行,点击确定,出错啦?什么错?如图:
由于是从一个新的线程调用UI线程中窗体控件,所以这个做法很危险,你直接被拒绝了。
有一个解决办法,就是让编译器不进行跨线程检查。
在Load代码第一行加一句:
CheckForIllegalCrossThreadCalls = False
再次运行程序,就不会有错了,你还能看见动态变化,并且没有“假死”:
如上就是线程的好处。
但是:
CheckForIllegalCrossThreadCalls = False
一句跨线程调用Windows窗体控件就万能了吗?毕竟这种方式很不优秀。
不然,请看下文。
2012年01月25日 05点01分 8
level 9
lipeiyi2006 楼主
我们再创建一个窗体Form2,放一个Label0,如图:
我希望通过Form1的按钮,让Form2中的Label0显示0~9000.
代码如下:
Form1:
Imports System.Threading
Public Class Form1
  Dim t As Thread
  Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
   Form2.Show()'启动时显示Form2
End Sub
  Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
   CheckForIllegalCrossThreadCalls = False
   t = New Thread(AddressOf test)
   t.Start()
  End Sub
  Private Sub test()
   For i = 0 To 9000
     Form2.Label0.Text = i.ToString '注意这里改了
   Next
   t.Abort()
  End Sub
End Class
//运行试试,咦?Form2里面怎么没变?
难道没有执行那句代码?
添加断点看看?
很明显执行了。但是就是没显示,程序不听话了?
CheckForIllegalCrossThreadCalls = False
没辙了吧?
看后文。
2012年01月25日 05点01分 9
这是为什么呢
2017年02月02日 02点02分
level 9
lipeiyi2006 楼主
跨两个UI调用,
CheckForIllegalCrossThreadCalls = False
确实不太给力,那么如何是好?
这里,我们就要用到“委托”和invoke?什么东东啊? 往后看。。。
在Form1里面添加委托声明代码(带一个参数),和控件更新过程(带一个参数),
在test中使用Me.Invoke调用委托,执行UpdateUI,并向里面传一个参数i
稍微修改一下,其余代码不变:
下面运行试试?你看到了什么?是不是动态变化了哦?
删除这一句:CheckForIllegalCrossThreadCalls = False 也行。

2012年01月25日 06点01分 10
楼主讲下委托吧。。。不会啊
2013年11月30日 12点11分
太好了,终于在线程里面用ui控件了
2015年03月12日 06点03分
level 9
lipeiyi2006 楼主
那么,像这样跨线程调用Windows窗体控件就实现了,并且这是被允许的安全方法。
有了线程和委托的联合,我们就能创建更加人性化的程序了,快速而又安全。
多线程的实现就是开很多线程罢了,记住最后一定要.Abort关闭线程,不然如果线程未结束,程序退出只是UI退出,线程还在呢....
读者请试试,有疑问请回帖。
[鼓掌]

2012年01月25日 06点01分 11
vb2010使用abort结束线程会有提示asynchronousthreadabort,而且有内存泄漏。但我这边让线程自主结束后,内存依然不能释放,gc.collect也不管用。。请问用什么方法结束线程比较安全?
2015年02月23日 11点02分
抱歉是不是挖坟了。。
2015年02月23日 11点02分
@19960607417HF 线程会自动结束,不必手动终止它。
2015年02月23日 13点02分
@lipeiyi2006 好吧我开成无限循环了
2015年02月24日 01点02分
level 13
请问1+1=?
2012年01月25日 06点01分 12
level 13
For...Next的速度很快的,楼主为何不用个Sleep()?
2012年01月31日 02点01分 14
level 13
为何楼主有绿色的竖线?
2012年01月31日 06点01分 15
level 9
lipeiyi2006 楼主
那是修改代码后保存代码IDE自动留下的“痕迹“,起到提醒作用。
2012年02月01日 15点02分 16
level 13
能详细讲一下委托吗?
2012年02月05日 01点02分 17
level 9
lipeiyi2006 楼主
上例看懂否?
2012年02月05日 04点02分 18
level 13
有些晕+——整体大致有感觉了[瀑布汗~]
2012年02月05日 05点02分 19
level 4
人气太少了,粉一下吧
[打酱油]
2012年02月24日 03点02分 20
1 2 3 尾页