如何知道一组线程是否已完成

时间:2015-06-22 17:34:21

标签: vb.net multithreading

我想知道各种线程是否完成了他们的工作,然后举起一个事件,我有以下代码:

Private Sub xTask(ByVal Value As String)
    Try
        Dim th As Thread

        For i As Integer = 1 To 254
            th = New Thread(Sub() YTask(Value + i))
            th.IsBackground = True
            th.Start()
        Next

        'If all threads have finished working, raise an event

    Catch ex As Exception
        Throw New Exception(ex.Message)
    End Try
End Sub

我非常擅长穿线,我几乎可以肯定这不是最好的方式,有人可以给我一些建议吗?

我正在使用Framework 2.0。

3 个答案:

答案 0 :(得分:4)

我不清楚你到底想要完成什么,所以很难推荐最佳实践。

但是对于你的要求,在你启动的每个线程上执行thread.Join()将确保你等待所有线程完成。

请参阅.NET 2.0 doc:https://msdn.microsoft.com/en-us/library/95hbf2ta(v=vs.80).aspx

您的代码看起来像这样:

Private Sub xTask(ByVal value As String)
    Dim threadList As List(Of Thread) = New List(Of Thread)

    For i As Integer = 1 To 254
        Dim t = New Thread(Sub() YTask(value))
        t.IsBackground = True ' not sure why you want this if you are going to wait for the thread to finish anyways.
        t.Start()
        threadList.Add(t)
    Next

    ' wait for all threads to finish.
    ' The loop will only exit once all threads have completed their work.
    For Each t In threadList
        t.Join()
    Next

    ' Raise event now that all the threads have completed.
End Sub

编辑:使线程数可调

通常,启动过多的线程来执行某些工作并不是最好的主意。此外,根据每个线程的工作资源密集程度,它可能会导致程序整体放缓。

通常,您希望测试哪个线程数量可以在更快和并行地完成工作与滥用系统资源和导致整体性能下降之间达到适当的平衡。

以下代码应该可以让您轻松调整执行工作的线程数,并为您找到合适的平衡点。

Sub Main()
    xTask("192.168.10.")
End Sub

Private Sub xTask(ByVal value As String)
    Dim ipAddressesToScan As Queue(Of String) = New Queue(Of String)

    SyncLock ipAddressesToScan ' I'm not 100% sure this locking is needed here, but I would do it to be safe, and it doesn't hurt.
        For i As Integer = 1 To 254
            ipAddressesToScan.Enqueue(value & i)
        Next
    End SyncLock

    Dim threadList As List(Of Thread) = New List(Of Thread)
    For i As Integer = 1 To 10 ' <-- change this to whatever number of threads seems to work best for you.
        Dim t = New Thread(Sub() YTask(ipAddressesToScan))
        't.IsBackground = True ' don't think you need this TBH.
        t.Start()
        threadList.Add(t)
    Next

    ' Wait for all threads to finish processing the queue.
    For Each t In threadList
        t.Join()
    Next

    ' Raise event HERE to signal that all the threads have completed.
    Console.WriteLine("All threads have finished their work")
End Sub

Private Sub YTask(ByVal ipAddressesToScan As Queue(Of String))
    Dim ipAddress As String
    Do
        SyncLock ipAddressesToScan
            If ipAddressesToScan.Count = 0 Then
                ipAddress = Nothing
            Else
                ipAddress = ipAddressesToScan.Dequeue
            End If
        End SyncLock

        If Not String.IsNullOrEmpty(ipAddress) Then
            ' Perform your scan here...
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId & " is scanning IP Address " & ipAddress)
        End If
    Loop While Not String.IsNullOrEmpty(ipAddress)
End Sub

答案 1 :(得分:1)

我会使用Task库(假设您使用的是.Net 4)。

将每个新任务添加到列表中,您可以等待所有内容完成一行,如下所示:

Private Sub xTask(ByVal Value As String)
    Try
        Dim task As Task
        Dim tasks As New List(Of Task)

        For i As Integer = 1 To 254
            task = New Task(Sub() YTask(Value))
            tasks.Add(task)
            task.Start()
        Next

        ' wait up to 5 seconds for all tasks to complete
        Task.WaitAll(tasks.ToArray, 5000)

    Catch ex As Exception
        Throw New Exception(ex.Message)
    End Try
End Sub

答案 2 :(得分:0)

好吧,我认为你打算在这里使用BackgroundWorker。完成后台工作程序处理(或者如果已取消),您可以举起RunWorkerCompleted事件。