VB.NET 在线程里用textbox,提示 线程间操作无效: 从不是创建控件“TextBox2”的线程访问它

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VB.NET 在线程里用textbox,提示 线程间操作无效: 从不是创建控件“TextBox2”的线程访问它相关的知识,希望对你有一定的参考价值。

看到MSDN上写着invoke,什么来着,本人菜鸟MSDN看不懂,还请大神写个示例,VB.NET的哦。谢谢

 比如在一个窗体中的代码如下,在另一个线程中显示,隐藏窗口线程中的进度条:  

     Public Delegate Sub VoidDelegate() '定义委托类型
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Dim th1 As New System.Threading.Thread(AddressOf MyThreadProc) '声明线程
        th1.Start() '启动线程运行 MyThreadProc过程
    End Sub
    Public Sub MyThreadProc() 
        Me.Invoke(New VoidDelegate(AddressOf StartProgress)) '这个是在另一个线程里调用StartProgress过程,并在创建窗口的那个线程里运行。参数是委托类型。me也可以改成控件名。如果直接调用 StartProgress,那该过程就在与MyThreadProc同一线程中运行,那么StartProgress过程中修改的控件不是在本线程创建的,就会出错。
       '。。。。。。。。。
        Me.Invoke(New VoidDelegate(AddressOf ShutProgress))
    End Sub
    Public Sub ShutProgress()
        ProgressBar1.Visible = False
   End Sub
    Public Sub StartProgress()
        ProgressBar1.Visible = True
    End Sub

'不是还有个Process控件吗,好像也是用来多线程操作的,还没研究,

参考技术A 在form_load事件中加上下面一句就好:
CheckForIllegalCrossThreadCalls = False '不进行跨线程检查,

VB.NET多线程入门

最近项目中遇到了一个处理速度慢堵塞用户界面操作的问题,因此想用多线程来解决。

在处理数据的循环中,新建线程,在新建的线程中处理数据。多线程同时处理数据,以此来达到加速的目的,使用户界面操作变得流畅。

在多任务操作系统中,我们可以在操作系统的协调下同时进行多个任务。各个任务以分时复用的形式来进行工作。Windows操作系统通过进程ID来管理各进程,每个进程至少包含一个线程,线程是进程中可以独立运行的程序片段。在主程序运行时,主程序可以启动线程,线程与主程序同时运行。线程是系统中分时处理的最小单位,也就是说线程可以与主程序并行运行,参与同分时处理。线程有自己独立的栈处理数据,它在与主程序同时运行时可以共享主程序定义的变量、函数。只有当线程运行结束才把控制权还给主程序。

创建线程最直接的方法是创建新的线程类实例,并使用Address Of语句为运行的过程传递委托。但是这种方法不能传递参数和返回值。

我们可以通过将在单独的线程中运行的过程包装到类或结构中,为它们提供参数,并使之能返回参数。

下面是一个新建线程的小demo:

Class TasksClass
    Public StrArg As String
    Public RetVal As Boolean
    Public resultFlag As Boolean

    Public Event ResultEvent(ByVal resultFlag As Boolean)

    Public Sub SomeTask()
        ' 将 StrArg 字段用作参数。
        MessageBox.show("StrArg 包含字符串" & StrArg)
        RetVal = True ' 设置返回参数的返回值。
    End Sub
End Class
Public Class Test

    Private Sub Test_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        DoWork()
    End Sub

    ' 要使用类,请设置存储参数的属性或字段,
    ' 然后,根据需要异步调用方法。
    Sub DoWork()
        Dim Tasks As New TasksClass()
        Dim Thread1 As New System.Threading.Thread(AddressOf Tasks.SomeTask)
        Tasks.StrArg = "参数A" ' 设置用作参数的字段。
        Thread1.Start() ' 启动新线程。
        Thread1.Join() ' 等待线程 1 运行结束。
        ' 显示返回值。
        MessageBox.show("线程 1 返回值" & Tasks.RetVal)

    End Sub
End Class

这样一个线程就被新建出来了。


但是事实上,创建过多的线程反而会影响性能,因为各个线程之间是分时复用的,操作系统需要在它们之间不断的切换,线程过多的时候,大量的时间消耗在线程切换上。

所以需要控制线程的数量。

假设我们只新建10个线程,剩余的数据等待这10个线程中的某个结束,再继续新建线程处理数据。使线程的总数一直保持在10个。

Public Class ThreadingObj
    Public paper As WorkSpace
    Public Sub ThreadingInsertPaper()
        '多线程处理数据
    End Sub
End Class
Private PaperList As List(Of WorkSpace) = New List(Of WorkSpace)
Dim ThreadingList As List(Of System.Threading.Thread) = New List(Of System.Threading.Thread)
For Each paper In PaperList
    '多线程处理PaperList
    If ThreadingList.Count < 10 Then  
    '不到10个线程则继续新起线程  
        Dim ThreadingObject As New ThreadingObj  
        Dim ThreadingTask_1 As New System.Threading.Thread(AddressOf ThreadingObject.ThreadingInsertPaper)  
        ThreadingObject.paper = paper  
        ThreadingList.Add(ThreadingTask_1)  
        ThreadingTask_1.Start() ' 启动新线程。  
    Else  
        Dim goOnFlag As Boolean = False  
        '循环等待有线程结束  
        Do  
            If CheckThreadingStatus() Then  
                '存在已完成的线程  
                If ThreadingList.Count <= 10 Then  
                    Dim ThreadingObject As New ThreadingObj  
                    Dim ThreadingTask_1 As New System.Threading.Thread(AddressOf ThreadingObject.ThreadingInsertPaper)  
                    ThreadingObject.paper = paper  
                    ThreadingList.Add(ThreadingTask_1)  
                    ThreadingTask_1.Start() ' 启动新线程。  
                    goOnFlag = True  
                End If  
            Else  
                '所有线程都在进行中  
            End If  
        Loop Until goOnFlag = True  
    End If
Next
Function CheckThreadingStatus() As Boolean
    '返回True表示存在已完成的线程
    If ThreadingList.Count <= 10 Then
        For Each ThreadingTaskItem In ThreadingList
            'ThreadingTaskItem.IsAlive
            If ThreadingTaskItem.IsAlive = False Then
                ThreadingTaskItem.Abort()
                ThreadingList.Remove(ThreadingTaskItem)
                Return True
            End If
        Next
    End If
    Threading.Thread.Sleep(100)
    If ThreadingList.Count <= 10 Then
        For Each ThreadingTaskItem In ThreadingList
            If ThreadingTaskItem.IsAlive = False Then
                Return True
            End If
        Next
    End If
    Return False
End Function

假设操作系统中有50个活跃的线程,如果我们的程序只有一个线程,那么程序就占用了系统资源的五十分之一。如果此时再多开一个线程,那么就占用了系统资源的2/51。我们的程序占用的资源越多,处理速度也就会更快一些。

因为各个线程之间是分时复用的,所以活跃的线程数量也会影响程序的效率。

有一种说法是2N + 2个线程数,是最有效率的。N是CPU的核数。但是这一说法也一直存在争议。

我的测试结果如下(我的电脑是i7 4770 ,四核八线程):

线程数123456789101115
耗时753409345316305286280282273273264266

测试的结果有点奇怪。。。。。。。

可能跟一些其他的因素也有关系。。。比如DB的状态,比如浏览网页对CPU的占用

以上是关于VB.NET 在线程里用textbox,提示 线程间操作无效: 从不是创建控件“TextBox2”的线程访问它的主要内容,如果未能解决你的问题,请参考以下文章

VB.NET 中的线程安全变量

VB.net 如何设计多线程运行

求教VB.net多线程问题

使用带有设计器对象的线程 vb.net

VB.NET连接access数据库文件时提示“无效的授权说明”

怎么在java main方法里用一个线程的sleep()方法让一个循环执行一次后阻塞一秒再循环下一次