我有两个并行运行的线程,一旦用户点击提交按钮(两个线程完成一项复杂的任务并需要大约10分钟才能完成),但在此过程中如果用户希望中止,我应该停止线程。我尝试使用线程的abort方法,但线程继续在后台运行,如果我重新启动应用程序,它会立即抛出错误。
答案 0 :(得分:0)
一种方法是通过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 H@cker
'
' 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