2014-03-18 54 views
2

我有两个并行运行的线程,一旦用户单击提交按钮(两个线程完成一项复杂的任务,需要大约10分钟才能完成),但在这个过程中,如果用户希望中止,我应该停止线程。我尝试了线程的放弃方法,但线程继续在后台运行,并立即如果我重新启动应用程序,它会抛出一个错误。如何在vb.net win窗体应用程序中正确地停止线程

+0

查看任务并行库(TPL)和取消令牌。您可以定期检查任务中的取消,如果由用户设置,则停止执行任何长时间运行的进程正在运行。 – Neolisk

回答

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 [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 
相关问题