Vb.net GUI上的多线程操作顺序
我目前正在编写一个程序,使用WGET从不同的服务器下载多个csv文件。每次下载都是一个新线程,因为我使用WaitForExit(10000)方法将WGET作为一个进程调用,所以WGET有10秒的下载时间。如果下载没有在这段时间内完成,线程将被终止,因为服务器没有及时响应 此外,还有一个listview,它记录我的程序目前正在做什么,以及哪个线程以哪个状态结束 这就是我的日志记录方法(lvw_log是我的ListView): 当文本必须从某个WGET线程添加到我的ListView时,将调用委托。”p'是自己类的一个对象,用于传递线程可访问的一组变量 我将每个线程存储在名为WGETThreadArray的ArrayList中:Vb.net GUI上的多线程操作顺序,vb.net,multithreading,Vb.net,Multithreading,我目前正在编写一个程序,使用WGET从不同的服务器下载多个csv文件。每次下载都是一个新线程,因为我使用WaitForExit(10000)方法将WGET作为一个进程调用,所以WGET有10秒的下载时间。如果下载没有在这段时间内完成,线程将被终止,因为服务器没有及时响应 此外,还有一个listview,它记录我的程序目前正在做什么,以及哪个线程以哪个状态结束 这就是我的日志记录方法(lvw_log是我的ListView): 当文本必须从某个WGET线程添加到我的ListView时,将调用委托。”
Dim WGETThreadArray As New ArrayList
For i = 0 to NumberOfFilesToDownload - 1
Dim WGETThread As New System.Threading.Thread(AddressOf StartWGET)
WGETThreadArray.Add(WGETThread)
Log("Starting thread " + i.ToString)
WGETThreadArray(i).Start(p)
Next
现在我想等待所有线程完成或中止:
Log("Waiting for threads to finish")
For i = 0 To WGETThreadArray.Count - 1
WGETThreadArray(i).Join()
Next
Log("All threads closed")
Log("Downloaded all DB-Info-Files")
线程(方法StartWGET)如下所示:
如您所见,方法“Log”在线程中被调用。问题是主线程总是在其他线程之前写入ListView。因此,我看到“所有线程都已关闭”一行,然后出现“线程已成功结束”这样的消息。尽管我在for循环中使用了.Join()方法。我想让它等到所有线程都完成
那么,如何使主线程暂停,直到所有其他WGET线程都完成。还有,在主线程接管并告诉我所有线程都已完成之前,如何让它们记录日志
我知道这很难解释,我真的希望我能说清楚。如果没有,请再次询问我,以便我更好地解释我自己。主线程被Join()调用阻塞,因此尝试切换到主线程的日志的BeginInvoke必须等待主线程变为可用(在所有连接之后)这意味着对日志的实际调用将在主线程可用后执行。这是在等待线程并记录“AllThreadsClosed”消息之后 调用等待新线程上的工作线程来释放主线程,以便只进行UI渲染。这是一个重要的原则:为了拥有一个响应性强的UI,让主线程只做很少的工作,并且从不阻塞它 你的陈述
WGETThreadArray(p.ThreadIndex).Abort()
没有意义,因为线程无论如何都会在例程结束时中止
另外,生成多个进程来下载多个文件可能不会比一次只下载一个文件更划算 你使用线程而不是更容易处理的任务有什么特别的原因吗?我使用线程是因为我不知道有什么更好的理由。但是为什么这不能与线程一起工作呢?使用
等待句柄
我不能说它不能与线程一起工作;)核对答案。但是任务有强大的方法,似乎可以满足您的问题。这些注释是red herrings()任务或线程、等待或连接,它们不会解决实际问题,因为UI线程被阻塞。
Public Sub StartWGET(p As Object)
'this method is called for each thread to parallely download the necessary files
Dim procInfo As New ProcessStartInfo(p.PathToWgetExe, p.ArgumentString)
procInfo.CreateNoWindow = False
procInfo.UseShellExecute = True
Dim WGETProcessHandler As System.Diagnostics.Process = System.Diagnostics.Process.Start(procInfo)
If Not WGETProcessHandler.WaitForExit(10000) Then 'if WGET doesn't finish within '10000' milliseconds, the thread gets killed
WGETProcessHandler.Kill()
Log("DB " + p.DBName + " was not loaded. Thread " + p.ThreadIndex.ToString + " killed ")
DatabaseArray(p.ThreadIndex).isLoaded = False
WGETThreadArray(p.ThreadIndex).Abort()
Else
DatabaseArray(p.ThreadIndex).isLoaded = True
Log(p.URL + " downloaded. Thread " + p.ThreadIndex.ToString + " ended successfully.")
End If
End Function
Log("Waiting for threads to finish")
Dim SomeAlive as boolean
do
Threading.Thread.Sleep(100)
SomeAlive = False
For i as integer = 0 To WGETThreadArray.Count - 1
if WGETThreadArray(i).IsALive then
SomeALive = True
Exit For
end if
Next
Loop While SomeAlive
WGETThreadArray(p.ThreadIndex).Abort()