多线程问题

Multi-threading Issue

我试图在线程中做一个简单的例子 此错误消息
谁能帮我解决一下?

跨线程操作无效:控件 'cmb1' 从创建它的线程以外的线程访问。

Imports System.Threading

Public Class Form1

Inherits System.Windows.Forms.Form

Dim th1 As Thread
Dim th2 As Thread

Private Sub Form1_Load (ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load

  th1 = New Thread(AddressOf proc1)
  th2 = New Thread(AddressOf proc2)

  th1.Start()
  th2.Start()

End Sub

Sub proc1()

  Dim iCount As Integer

  For iCount = 1 To 10
    cmb1.Items.Add(iCount)
  Next

End Sub

Sub proc2()

  Dim iCount As Integer

  For iCount = 11 To 20
    cmb2.Items.Add(iCount)
  Next

End Sub

End Class

使用Control.CheckForIllegalCrossThreadCalls属性

当控件的创建线程以外的线程试图访问该控件的方法或属性之一时,通常会导致不可预知的结果。常见的无效线程 activity 是对访问控件句柄 属性.

的错误线程的调用

将 CheckForIllegalCrossThreadCalls 设置为 true 以在调试时更轻松地查找和诊断此线程activity。

猜测 cmb1 是一个列表框之类的...您不能在不同的线程中操作物理对象。只能编辑变量等抽象对象

改为将整数放入列表中,并为线程完成时创建一个变量。

Dim IntList As New List(Of Integer)
Dim ThreadDone As Boolean = False

然后在线程中进行编码。

For iCount = 1 To 10
    IntList.Add(iCount)
Next
ThreadDone = True

使用计时器检查线程何时完成。或者,使用 BackgroundWorker 而不是 New Thread。 BackgroundWorker 将执行多线程处理并在完成后触发 RunWorkerCompleted 事件。

Private Sub Timer1_Tick()
    If ThreadDone = True
        cmb1.AddRange(IntList)
    End If
End Sub

您需要确保以线程安全的方式访问控件。当您 运行 应用程序时,它使用单个默认线程来创建控件和进行处理。您的组合框控件是使用此默认线程创建的。当您尝试使用新线程向组合框添加项目时,这违反了线程安全规则,因为您只能从创建组合框的线程更改组合框。为此,您需要查看 InvokeRequired 属性 的值以检查您是否需要从不同的线程访问。如果需要调用(如本例所示),则调用 Invoke 方法并传递一个委托对象。委托被指向同一个子例程,但这次它将 运行 它作为默认线程并且不会再发生 "Cross-thread operation not valid" 错误。您可以在这里阅读更多相关信息:http://msdn.microsoft.com/en-us/library/ms171728%28v=vs.85%29.aspx

此外,您应该如何重写代码以合并委托调用:

Imports System.Threading

Public Class Form1
    Inherits System.Windows.Forms.Form

    Dim th1 As Thread
    Dim th2 As Thread
    ' Create the delegates that are needd to make safe thread calls
    Private Delegate Sub proc1Delegate()
    Private Delegate Sub proc2Delegate()

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        th1 = New Thread(AddressOf proc1)
        th2 = New Thread(AddressOf proc2)
        th1.Start()
        th2.Start()
    End Sub

    Sub proc1()
        ' Check if invoke is required
        If Me.InvokeRequired Then
            ' An invoke is required so we call the delegate and point back to the same subroutine
            Me.Invoke(New proc1Delegate(AddressOf proc1))
        Else
            ' Original code goes only gets run on default thread
            Dim iCount As Integer
            For iCount = 1 To 10
                cmb1.Items.Add(iCount)
            Next
        End If
    End Sub

    Sub proc2()
        ' Check if invoke is required
        If Me.InvokeRequired Then
            ' An invoke is required so we call the delegate and point back to the same subroutine
            Me.Invoke(New proc2Delegate(AddressOf proc2))
        Else
            ' Original code goes only gets run on default thread
            Dim iCount As Integer
            For iCount = 11 To 20
                cmb2.Items.Add(iCount)
            Next
        End If
    End Sub
End Class