2
我有兩個並行運行的線程,一旦用戶單擊提交按鈕(兩個線程完成一項複雜的任務,需要大約10分鐘才能完成),但在這個過程中,如果用戶希望中止,我應該停止線程。我嘗試了線程的放棄方法,但線程繼續在後臺運行,並立即如果我重新啓動應用程序,它會拋出一個錯誤。如何在vb.net win窗體應用程序中正確地停止線程
我有兩個並行運行的線程,一旦用戶單擊提交按鈕(兩個線程完成一項複雜的任務,需要大約10分鐘才能完成),但在這個過程中,如果用戶希望中止,我應該停止線程。我嘗試了線程的放棄方法,但線程繼續在後臺運行,並立即如果我重新啓動應用程序,它會拋出一個錯誤。如何在vb.net win窗體應用程序中正確地停止線程
一種方式來做到這一點是通過API使用:OpenThread function + SuspendThread function + ResumeThread function + CloseHandle function
另一種方式來做到這一點是:ManualResetEvent Class和/或AutoResetEvent Class
我寫的時候以前是暫停/恢復外部進程的線程的代碼片段,您可以看到上面的文檔編寫自己的代碼,在Google中搜索示例,或者編輯下面的代碼片段以滿足您的需求:
#Region " Pause-Resume Thread Class "
' [ Pause-Resume Thread Functions ]
'
' // By Elektro [email protected]
'
' Examples :
'
' Process_Thread.Pause_Thread("ffmpeg.exe") ' Pause ffmpeg.exe (with thread 0)
' Process_Thread.Resume_Thread("ffmpeg.exe") ' Resume ffmpeg.exe (with thread 0)
' Process_Thread.Pause_Thread("cmd.exe", , True) ' Pause all instances of cmd.exe (with thread 0)
' Process_Thread.Resume_Thread("cmd.exe", , True) ' Resume all instances of cmd.exe (with thread 0)
' Process_Thread.Pause_Thread("Process.exe", 2) ' Pause the thread 2 of "Process.exe"
' Process_Thread.Resume_Thread("Process.exe", 2) ' Resume the thread 2 of "Process.exe"
' MsgBox(Process_Thread.Thread_Handle_Dictionary.Count)
Public Class Process_Thread
<System.Runtime.InteropServices.DllImport("kernel32.dll")> _
Private Shared Function OpenThread(ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Boolean, ByVal dwThreadId As UInt32) As IntPtr
End Function
<System.Runtime.InteropServices.DllImport("kernel32.dll")> _
Private Shared Function SuspendThread(hThread As IntPtr) As UInteger
End Function
<System.Runtime.InteropServices.DllImport("kernel32.dll")> _
Private Shared Function ResumeThread(hThread As IntPtr) As UInt32
End Function
<System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function CloseHandle(ByVal hObject As IntPtr) As <System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean
End Function
''' <summary>
''' Dictionary to store the current paused threads.
''' </summary>
Public Shared Thread_Handle_Dictionary As New Dictionary(Of String, IntPtr)
#Region " Pause Thread "
''' <summary>
''' Function to pause a thread.
''' </summary>
'''
''' <param name="Process_Name">The name of the process, ex: cmd.exe</param>
''' <param name="Thread_Number">The thread to pause, ex: 0</param>
''' <param name="Recursive"> <value name="True">Pause the thread in all processes found recursively.</value></param>
''' <returns>True if the process is found; otherwise, False.</returns>
Public Shared Function Pause_Thread(ByRef Process_Name As String, _
Optional ByVal Thread_Number As Int32 = 0, _
Optional ByVal Recursive As Boolean = False) As Boolean
If Process_Name.ToLower.EndsWith(".exe") Then _
Process_Name = Process_Name.Substring(0, Process_Name.Length - 4)
Dim proc() As Process = Process.GetProcessesByName(Process_Name)
If Not proc.Length = 0 Then
If Recursive Then
For proc_num As Integer = 0 To proc.Length - 1
Try
Thread_Handle_Dictionary.Add(Process_Name.ToLower & Thread_Number.ToString & ";" & proc(proc_num).Handle.ToString, _
OpenThread(&H2, True, proc(proc_num).Threads(Thread_Number).Id))
SuspendThread(Thread_Handle_Dictionary.Item(Process_Name.ToLower & Thread_Number.ToString & ";" & proc(proc_num).Handle.ToString))
Application.DoEvents()
Catch ex As Exception
MsgBox(ex.Message) ' The handle already exist in the Dictionary.
Return False
End Try
Next
Else
Try
Thread_Handle_Dictionary.Add(Process_Name.ToLower & Thread_Number.ToString & ";" & proc(0).Handle.ToString, _
OpenThread(&H2, True, proc(0).Threads(Thread_Number).Id))
SuspendThread(Thread_Handle_Dictionary.Item(Process_Name.ToLower & Thread_Number.ToString & ";" & proc(0).Handle.ToString))
Catch ex As Exception
MsgBox(ex.Message) ' The handle already exist in the Dictionary.
Return False
End Try
End If
Else ' proc.Length = 0
Throw New Exception("Process """ & Process_Name & """ not found.")
Return False
End If
Return True
End Function
#End Region
#Region " Resume Thread "
''' <summary>
''' Function to resume a thread.
''' </summary>
'''
''' <param name="Process_Name">The name of the process, ex: cmd.exe</param>
''' <param name="Thread_Number">The thread to resume, ex: 0</param>
''' <param name="Recursive"> <value name="True">Resume the thread in all processes found recursively.</value></param>
''' <returns>True if the process is found; otherwise, False.</returns>
Public Shared Function Resume_Thread(ByRef Process_Name As String, _
Optional ByVal Thread_Number As Int32 = 0, _
Optional ByVal Recursive As Boolean = False) As Boolean
If Process_Name.ToLower.EndsWith(".exe") Then _
Process_Name = Process_Name.Substring(0, Process_Name.Length - 4)
Dim Process_Exist As Boolean = False ' To check if process exist in the dictionary.
Dim Temp_Dictionary As New Dictionary(Of String, IntPtr) ' Replic of the "Thread_Handle_Dictionary" dictionary.
For Each Process In Thread_Handle_Dictionary
If Process.Key.StartsWith(Process_Name.ToLower & Thread_Number.ToString) Then Process_Exist = True
Temp_Dictionary.Add(Process.Key, Process.Value)
Next
If Process_Exist Then
If Recursive Then
For Each Process In Temp_Dictionary
If Process.Key.ToLower.Contains(Process_Name.ToLower & Thread_Number.ToString) Then
ResumeThread(Process.Value)
CloseHandle(Process.Value)
Thread_Handle_Dictionary.Remove(Process.Key)
End If
Application.DoEvents()
Next
Else
For Each Process In Temp_Dictionary
If Process.Key.ToLower.Contains(Process_Name.ToLower & Thread_Number.ToString) Then
ResumeThread(Process.Value)
CloseHandle(Process.Value)
Thread_Handle_Dictionary.Remove(Process.Key)
Exit For
End If
Application.DoEvents()
Next
End If
Return True
Else
Throw New Exception("Process """ & Process_Name & """ with thread number """ & Thread_Number & """ not found.")
Return False
End If
End Function
#End Region
End Class
#End Region
查看任務並行庫(TPL)和取消令牌。您可以定期檢查任務中的取消,如果由用戶設置,則停止執行任何長時間運行的進程正在運行。 – Neolisk