WaitHandle.WaitAll Выполняется до завершения всех потоков - VB.Net 4.0 - PullRequest
0 голосов
/ 27 января 2011

Я работаю над программой, которая сканирует список серверов на предмет разной информации.

Все работает нормально, но иногда я получаю ошибки, когда потоки завершены.Либо после завершения сканирования, либо с помощью кнопки отмены, которая останавливает цикл, но позволяет текущим потокам продолжаться.

Я вижу, что пользовательский интерфейс говорит, что сканирование завершено, но progressUpdate пытается снова запустить.Я могу решить эту проблему, сделав более длинный поток. После ожидания.

В большинстве случаев он ожидает последнего потока, но иногда я получаю сообщение о том, что не может получить доступ к функции 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

Редактировать Массив пуст, когда я ломаю его.Но как-то что-то работает до сих пор.Может быть, мне не хватает ловить одного.

1 Ответ

1 голос
/ 25 февраля 2011

Почти всех сложностей в вашем коде можно избежать с помощью нового метода Parallel.ForEach в .Net 4. Это избавит от необходимости поддерживать WaitHandles, а также предложит простой механизм для ограничить максимальное количество потоков, если вы того пожелаете.

...