2014-03-18 52 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 
相關問題