多线程问题

时间:2015-01-04 01:47:44

标签: vb.net multithreading

我试图在线程中做一个简单的例子 这个错误消息 有人可以帮我解决吗?

跨线程操作无效:控制' 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

3 个答案:

答案 0 :(得分:2)

您需要确保以线程安全的方式访问控件。当您运行应用程序时,它使用单个默认线程来创建控件并进行处理。您正在使用此默认线程创建组合框控件。当您尝试使用新线程将项目添加到组合框时,它违反了线程安全规则,因为您只能从创建它们的线程更改组合框。为此,您需要查看InvokeRequired属性的值,以检查是否需要从其他线程进行访问。如果需要调用(在这种情况下),则调用Invoke方法并传递委托对象。委托被指向相同的子例程,但这次它将作为默认线程运行,并且不再发生“跨线程操作无效”错误。您可以在此处详细了解: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

答案 1 :(得分:-1)

使用Control.CheckForIllegalCrossThreadCalls属性

当控件的创建线程以外的线程尝试访问该控件的某个方法或属性时,通常会导致不可预测的结果。一个常见的无效线程活动是在错误的线程上调用访问控件的Handle属性。

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

答案 2 :(得分:-1)

猜测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