WaitHandle.WaitAll 在所有线程完成之前运行 - VB.Net 4.0

发布于 2024-10-14 04:53:34 字数 2360 浏览 7 评论 0原文

我正在开发一个程序,该程序可以扫描服务器列表以获取不同信息。

一切工作正常,除了有时在线程完成时出现错误。通过扫描完成或取消按钮停止循环但让当前线程继续。

我看到用户界面显示扫描已完成,但 ProgressUpdate 尝试再次运行。 我可以通过在 waitall 之后设置更长的 thread.sleep 来解决问题。

在大多数情况下,它会等待最后一个线程,但有时会出现错误,说它无法访问 ProgressUpdate 函数,因为 OperationsComplete 已经运行。

我在下面的 BackgroundWorker1.ReportProgress(_completedCount, ScanResult) 处收到错误,但它不应该调用该错误,因为 WaitAll 应该等待线程完成。

Private Sub ScanIsDone(ByVal ar As IAsyncResult)
    Dim d As PingDelegate = DirectCast(ar.AsyncState, PingDelegate)
    Dim ScanResult As ServerInfo = d.EndInvoke(ar)

    SyncLock (_lockObject)
        _completedCount = _completedCount + 1
        BackgroundWorker1.ReportProgress(_completedCount, ScanResult)
    End SyncLock
End Sub



Private Sub BackgroundWorker1_DoWork (ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

    Dim servers As List(Of ServerInfo) = DirectCast(e.Argument, List(Of ServerInfo))
    Dim waitHandles As New List(Of WaitHandle)
    Dim waitHandles2 As New List(Of WaitHandle)
    Dim waitHandles3 As New List(Of WaitHandle)
    Dim waitHandles4 As New List(Of WaitHandle)

    For Each server As ServerInfo In servers
        _ThreadsOpen += 1
        _WaitCountAll += 1
        Dim d As New PingDelegate(AddressOf ScanServer)
        Dim ar As IAsyncResult = d.BeginInvoke(server, AddressOf ScanIsDone, d)
        Select Case _WaitCountAll
            Case 1 To 64
                waitHandles.Add(ar.AsyncWaitHandle)
            Case 65 To 128
                waitHandles2.Add(ar.AsyncWaitHandle)
            Case 129 To 192
                waitHandles3.Add(ar.AsyncWaitHandle)
            Case 193 To 256
                waitHandles4.Add(ar.AsyncWaitHandle)
        End Select

        While _ThreadsOpen > _ThreadMax - 1
            Thread.Sleep(200)
        End While
        If Cancel_Scan = True Then Exit For

    Next

    If waitHandles.Count <> 0 Then WaitHandle.WaitAll(waitHandles.ToArray())
    If waitHandles2.Count <> 0 Then WaitHandle.WaitAll(waitHandles2.ToArray())
    If waitHandles3.Count <> 0 Then WaitHandle.WaitAll(waitHandles3.ToArray())
    If waitHandles4.Count <> 0 Then WaitHandle.WaitAll(waitHandles4.ToArray())

    Thread.Sleep(1000)

End Sub

编辑当我破坏数组时它是空的。但不知怎的,有些东西仍然在运行。也许我错过了抓住一个。

I'm working on a program that scans a list of servers for different information.

Everything is working fine except sometimes I get errors when the threads are done. Either by the scan completing or the cancel button stopping the loop but letting the current threads continue.

I see the UI say the scan is complete but the progressUpdate tries to run again.
I can solve the problem by making a longer thread.sleep after the waitall.

For the most part it waits to the last thread but I get an error sometimes saying it can't access the progressUpdate function because OperationsComplete has already been run.

I get the error at BackgroundWorker1.ReportProgress(_completedCount, ScanResult) below but it shouldn't be calling that because WaitAll should wait until the threads are complete.

Private Sub ScanIsDone(ByVal ar As IAsyncResult)
    Dim d As PingDelegate = DirectCast(ar.AsyncState, PingDelegate)
    Dim ScanResult As ServerInfo = d.EndInvoke(ar)

    SyncLock (_lockObject)
        _completedCount = _completedCount + 1
        BackgroundWorker1.ReportProgress(_completedCount, ScanResult)
    End SyncLock
End Sub



Private Sub BackgroundWorker1_DoWork (ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

    Dim servers As List(Of ServerInfo) = DirectCast(e.Argument, List(Of ServerInfo))
    Dim waitHandles As New List(Of WaitHandle)
    Dim waitHandles2 As New List(Of WaitHandle)
    Dim waitHandles3 As New List(Of WaitHandle)
    Dim waitHandles4 As New List(Of WaitHandle)

    For Each server As ServerInfo In servers
        _ThreadsOpen += 1
        _WaitCountAll += 1
        Dim d As New PingDelegate(AddressOf ScanServer)
        Dim ar As IAsyncResult = d.BeginInvoke(server, AddressOf ScanIsDone, d)
        Select Case _WaitCountAll
            Case 1 To 64
                waitHandles.Add(ar.AsyncWaitHandle)
            Case 65 To 128
                waitHandles2.Add(ar.AsyncWaitHandle)
            Case 129 To 192
                waitHandles3.Add(ar.AsyncWaitHandle)
            Case 193 To 256
                waitHandles4.Add(ar.AsyncWaitHandle)
        End Select

        While _ThreadsOpen > _ThreadMax - 1
            Thread.Sleep(200)
        End While
        If Cancel_Scan = True Then Exit For

    Next

    If waitHandles.Count <> 0 Then WaitHandle.WaitAll(waitHandles.ToArray())
    If waitHandles2.Count <> 0 Then WaitHandle.WaitAll(waitHandles2.ToArray())
    If waitHandles3.Count <> 0 Then WaitHandle.WaitAll(waitHandles3.ToArray())
    If waitHandles4.Count <> 0 Then WaitHandle.WaitAll(waitHandles4.ToArray())

    Thread.Sleep(1000)

End Sub

Edit The array is empty when i break it. But somehow something runs still. Maybe I am missing catching one.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

岁吢 2024-10-21 04:53:34

通过使用新的 Parallel.ForEach 方法。这将消除维护 WaitHandles 的需要,并提供一种简单的机制来限制最大线程数(如果您愿意)选择。

Nearly all of the complexity in your code can be avoided by using the new Parallel.ForEach method in .Net 4. This will eliminate the need to maintain WaitHandles, as well as offering an easy mechanism to limit the maximum number of threads if you so choose.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文