VB.NET学习笔记:多线程编程

在《多线程加委托实现等待窗体(loading正在加载界面),运行超时可以取消操作》一文中使用到了多线程编程,在这里做个笔记。
我们继续使用《再谈委托——同步、异步、Lambda 表达式和内置委托》一文的示例代码为本文示例。原文中使用异步委托调用同步方法,即:

 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '暂时移除Button1按钮点击事件
        RemoveHandler Button1.Click, AddressOf Button1_Click

        '******************************************
        Dim method As MethodInvoker = Sub()
                                          '模拟长时间工作代码
                                          For i As Integer = 0 To 100
                                              '模拟长时间工作
                                              Threading.Thread.Sleep(100)

                                              '显示工作进度
                                              Dim Actiondelegate As Action(Of Integer) = Sub(int)
                                                                                             Me.Label1.Text = int.ToString & "%"
                                                                                         End Sub
                                              Me.Label1.Invoke(Actiondelegate, i)
                                          Next
                                      End Sub
        method.BeginInvoke(Nothing, Nothing)
        '******************************************

        '工作结束后记得恢复Button1按钮点击事件
        AddHandler Button1.Click, AddressOf Button1_Click
    End Sub

现修改为线程,代码如下:

Private th As Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '暂时移除Button1按钮点击事件
        RemoveHandler Button1.Click, AddressOf Button1_Click



        '******************************************
        th = New Thread(New ThreadStart(Sub()
                                            '模拟长时间工作代码
                                            For i As Integer = 0 To 100
                                                '模拟长时间工作
                                                Threading.Thread.Sleep(100)

                                                '显示工作进度
                                                Dim Actiondelegate As Action(Of Integer) = Sub(int)
                                                                                               Me.Label1.Text = int.ToString & "%"
                                                                                           End Sub
                                                Me.Label1.Invoke(Actiondelegate, i)
                                            Next
                                        End Sub))
        th.Start()
        '******************************************

        '工作结束后记得恢复Button1按钮点击事件
        AddHandler Button1.Click, AddressOf Button1_Click
    End Sub

运行代码,与异步委托效果一致,尝试运行中途关闭窗体,报错了:System.ComponentModel.InvalidAsynchronousStateException:“调用方法时发生错误。 目标线程不再存在。”,如图:
在这里插入图片描述
这是因为Me.Label1.Invoke(Actiondelegate, i)代码需在主线程(UI线程)执行,而关闭窗体后主线程已经销毁了,但子线程th还在继续运行,所以报错。应该在关闭窗体的同时关闭子线程th。添加如下代码:

Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
        If th.ThreadState <> ThreadState.Stopped Then
            th.Abort()
        End If
    End Sub

多点击几次按钮,还是会报错,可能是运行了多个子线程,但只关闭了一个,最好的办法是设置线程为后台线程,当主线程关闭时后台线程也会一同关闭,在th.Start()语句之前加入th.IsBackground = True即可。
以上是使用Lambda 表达式,你也可以使用AddressOf关联委托的方法。如下:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '暂时移除Button1按钮点击事件
        RemoveHandler Button1.Click, AddressOf Button1_Click

        '******************************************
        th = New Thread(AddressOf aa)
        th.IsBackground = True '后台线程
        th.Start()
        '******************************************

        '工作结束后记得恢复Button1按钮点击事件
        AddHandler Button1.Click, AddressOf Button1_Click
    End Sub
    
    Private Sub aa()
        SyncLock lockObj
            For i As Integer = 0 To 100
                '模拟长时间工作
                Threading.Thread.Sleep(100)

                '显示工作进度
                'Me.Label1.Text = i.ToString & "%"
                '修改为
                Dim Actiondelegate As Action(Of Integer) = New Action(Of Integer)(AddressOf bb)
                Me.Label1.Invoke(Actiondelegate, i)
            Next
        End SyncLock
    End Sub

    Private Sub bb(ByVal int As Integer)
        '显示工作进度
        Me.Label1.Text = int.ToString & "%"
    End Sub

可见,使用多线程编程并没有想象中的那么难,其实与使用委托类似:
首先,你需引入命名空间:Imports System.Threading
其次,定义一个线程,很简单:Dim th As Thread
然后实例化,可以使用AddressOf或Lambda 表达式。th = New Thread(AddressOf 过程名)
然后使用Start方法运行线程:th.Start()
使用ThreadState或IsAlive属性监控线程状态,采用处理措施,如使用Abort方法关闭线程:th.Abort()

以下是线程常用的命令:

命令 含义

Start 引起线程开始运行

Sleep 暂停线程一段时间。格式:Thread.Sleep(毫秒数)

Suspend 线程到达安全点时暂停线程

Abort 停止线程

Resume 重新启动暂停的线程

Join 引起当前线程等待另一个线珵结果

下表是线程常用属性:

属性 值

IsAlive 如果线程是活动的,值为True

IsBackgroud 获取或设置一个布尔值,表示某个线程是否允许是后台线程

Name 获取或设置线程的名称

Priority 获取或设置一个操作系统用于区分线程调用的优先级

ApartmentState 获取或设置特定线程使用的线程模型

ThreadState 包含描述线程状态的值
有关线程下操作窗体及线程同步请参考《再谈委托——同步、异步、Lambda 表达式和内置委托》。
更多多线程编程博文,请参考:
1、使用VB.NET开发多线程
2、VB.NET多线程
3、线程的坎坷人生
4、【VB.NET2010】多线程程序编写技术分析
5、官方帮助《托管线程处理

猜你喜欢

转载自blog.csdn.net/zyjq52uys/article/details/89326934
今日推荐