我目前正在编写一个使用WGET从不同服务器下载多个csv-Files的程序。每次下载都是一个新线程,因为我使用WaitForExit(10000)方法将WGET称为进程,因此WGET有10秒的时间下载。如果下载没有在该时间内完成,则线程被杀死,因为服务器没有及时回答。
此外,还有一个列表视图,记录我的程序当前正在执行的操作以及哪个线程以哪种状态结束。
这是我记录的方法(lvw_log是我的ListView):
Public Delegate Sub LogDelegate(ByVal Text As String)
Public Sub Log(Text As String)
If lvw_Log.InvokeRequired Then
lvw_Log.BeginInvoke(New LogDelegate(AddressOf Log), New Object() {Text})
Else
lvw_Log.Items.Add(DateTime.Now + ": " + Text)
lvw_Log.TopIndex = lvw_Log.Items.Count - 1
lvw_Log.Refresh()
End If
End Sub
当必须从其中一个WGET-Threads将文本添加到我的ListView时,将调用该委托。 'p'是一个自己类的对象,用于移交一组可供线程访问的变量。
我将每个线程存储在一个名为WGETThreadArray的ArrayList中:
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)是这样的:
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”。问题是主线程总是在其他线程之前写入ListView。所以我在“线程已成功结束”之类的消息之前看到“所有线程已关闭”行。虽然我在for-Loop中使用了.Join()方法。我想让它等到所有线程都完成。
那么在完成所有其他WGET-Thread之前,如何让主线程暂停。而且,如何在主线程接管之前让它们记录并告诉我所有线程都已完成。
我知道很难解释,我真的希望自己清楚明白。如果没有,请再次问我,这样我就能更好地解释自己。
答案 0 :(得分:0)
主要线程被Join()调用阻塞,因此尝试切换到主线程的Log的BeginInvoke必须等待主线程变为可用(在所有连接之后)这意味着实际在主线程可用后,将执行对Log的调用。那是在等待线程并记录"所有线程关闭后#34;消息
在新线程上调用等待工作线程以释放主线程以执行仅 UI呈现。这是一个重要的原则:拥有一个响应式UI,让主线程只做很少的工作,永远不会阻止它。
答案 1 :(得分:0)
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()
毫无意义,因为线程无论如何都会在例程结束时中止。
同时产生多个进程来下载多个文件可能不会让你一次只做一个。