VB.NET中多线程更新变量

时间:2014-09-04 09:58:34

标签: vb.net multithreading

我写了一个程序,它在启动时从Active Directory加载计算机列表。这大约需要10秒钟。如果用户已使用特定主机作为参数启动程序,则应立即使用该程序。 因此,不要中断用户我想在另一个线程中加载计算机列表。问题是它写入一个也在主线程中使用的变量(计算机列表)。 你可能会想,我可以简单地使用一个临时变量,当它完成时会覆盖主变量。但我必须保留主要变量的现有数据。

'hosts list
Private Shared hosts As New SortedDictionary(Of String, HostEntry)

'Get all computers in Active Directory
'Will run in a extra thread
Private Delegate Sub GetADcomputersDelegate()
Private Sub GetADcomputers()
    If Me.InvokeRequired Then
        Me.Invoke(New GetADcomputersDelegate(AddressOf GetADcomputers), Nothing)
    Else
        lblStatusAD.Text = "Getting Computers..."
        Try
            Dim search As New DirectorySearcher(ActiveDirectory.Domain.GetCurrentDomain().GetDirectoryEntry(), "(objectClass=computer)")
            For Each host As SearchResult In search.FindAll()
                'AddHost creates a new HostEntry object and adds it to my "global" hosts variable
                'It also checks if a host is already present in the list and only updates it.
                AddHost(host.GetDirectoryEntry().Properties("cn").Value.ToLower(), host.GetDirectoryEntry().Properties("description").Value)
            Next
        Catch ex As Exception
            Debug.WriteLine("GetADcomputers() Exception: " & ex.Message)
        End Try
        ThreadPool.SetMaxThreads(hosts.Count, hosts.Count)
        Dim ah As String = activehost
        'Fill my ListBox with the computers
        lstHosts.DataSource = New BindingSource(hosts, Nothing)
        'Select the computer that was selected before
        UseHost(ah)
        lblStatusAD.Text = ""
    End If
End Sub

因此当GetADcomputers()在自己的线程中运行时,主线程也会被阻塞。我猜是因为auf是hosts变量。

那么我可以改变什么来让线程完成它的工作,之后应用更新的计算机列表而不会丢失旧hosts列表中条目的数据?所有这一切都以快速有效的方式进行。

1 个答案:

答案 0 :(得分:1)

那段代码非常错误。如果在辅助线程上调用该方法,则它会立即将调用回调到UI线程并在UI线程上执行所有操作。您应该做的是在辅助线程上执行所有后台工作,然后仅编组到UI线程以更新UI。

摆脱那个If...Else块,然后让方法的整个主体在Else块中成为当前的。接下来,识别与UI特定交互的所有行,并将每个行移除到他们自己的方法中。然后,为每个方法添加If...Else块,以便只在UI线程上执行实际触摸UI的代码。

这是一个开始:

Private Sub GetADcomputers()
    UpdateStatusADLabel("Getting Computers...")
    Try
        Dim search As New DirectorySearcher(ActiveDirectory.Domain.GetCurrentDomain().GetDirectoryEntry(), "(objectClass=computer)")
        For Each host As SearchResult In search.FindAll()
            'AddHost creates a new HostEntry object and adds it to my "global" hosts variable
            'It also checks if a host is already present in the list and only updates it.
            AddHost(host.GetDirectoryEntry().Properties("cn").Value.ToLower(), host.GetDirectoryEntry().Properties("description").Value)
        Next
    Catch ex As Exception
        Debug.WriteLine("GetADcomputers() Exception: " & ex.Message)
    End Try
    ThreadPool.SetMaxThreads(hosts.Count, hosts.Count)
    Dim ah As String = activehost
    'Fill my ListBox with the computers
    lstHosts.DataSource = New BindingSource(hosts, Nothing)
    'Select the computer that was selected before
    UseHost(ah)
    lblStatusAD.Text = ""
End Sub

Private Sub UpdateStatusADLabel(text As String)
    If lblStatusAD.InvokeRequired Then
        lblStatusAD.Invoke(New Action(Of String)(AddressOf UpdateStatusADLabel), text)
    Else
        lblStatusAD.Text = text
    End If
End Sub