【问题标题】:What is the difference between p.WaitForExit() and p.WaitForExit(Integer.MaxValue) in this specific case?在这种特定情况下, p.WaitForExit() 和 p.WaitForExit(Integer.MaxValue) 有什么区别?
【发布时间】:2014-11-13 16:19:05
【问题描述】:

基本上我正在异步启动Process,我正在等待Process 使用Task 退出,下面的代码没有任何问题,但我发现了一点我想了解的问题...

问题是,如果我使用 process.WaitForExit() 方法并尝试取消 Task (或者相同的方法,杀死进程),那么进程永远不会退出,因此子线程将永远挂起,而不是如果我使用 process.WaitForExit(Integer.MaxValue) 方法,一切都会完美。

为什么会这样?,有什么区别导致进程无法识别进程已经退出?。

Process 实例:

''' <summary>
''' The CMD <see cref="System.Diagnostics.Process"/> instance.
''' </summary>
Private WithEvents cmdProcess As New Process With
   {
       .EnableRaisingEvents = True,
       .StartInfo = New ProcessStartInfo With
                        {
                           .FileName = "cmd.exe",
                           .Arguments = String.Empty,
                           .RedirectStandardInput = False,
                           .RedirectStandardOutput = True,
                           .RedirectStandardError = True,
                           .UseShellExecute = False,
                           .CreateNoWindow = True
                        }
   }

Task 初始化器:

Private Sub StartTask()

   Me.cmdTask = Task.Factory.StartNew(AddressOf CMDAutomate)
   Me.cmdTaskCTS = New Threading.CancellationTokenSource
   Me.cmdTaskCT = cmdTaskCTS.Token

End Sub

Task 所做的工作:

Private Sub CMDAutomate()

   With Me.cmdProcess

       .StartInfo.Arguments = String.Format("/C ""{0}""", Me.PingArguments)
       .Start()
       .BeginOutputReadLine()
       .BeginErrorReadLine()
       .WaitForExit(Integer.MaxValue)

   End With

End Sub

还有Task 取消器:

Private Sub CancelTask()

   If Not Me.cmdProcess.HasExited Then

       With Me.cmdProcess
           .CancelOutputRead()
           .CancelErrorRead()
           .Kill() ' kill process (cmd.exe)
       End With

       ' cancel the task.
       Me.cmdTaskCTS.Cancel()
       ' wait for the task cancellation finishes.
       Me.cmdTask.Wait()

   End If

End Sub

如果需要,这是整个代码:

Imports System.Threading
Imports System.Threading.Tasks

Public Class Form1

   Private cmdTask As Task
   Private cmdTaskCTS As New CancellationTokenSource
   Private cmdTaskCT As CancellationToken

   ''' <summary>
   ''' The CMD <see cref="System.Diagnostics.Process"/> instance.
   ''' </summary>
   Private WithEvents cmdProcess As New Process With
       {
           .EnableRaisingEvents = True,
           .StartInfo = New ProcessStartInfo With
                            {
                               .FileName = "cmd.exe",
                               .Arguments = String.Empty,
                               .RedirectStandardInput = False,
                               .RedirectStandardOutput = True,
                               .RedirectStandardError = True,
                               .UseShellExecute = False,
                               .CreateNoWindow = True
                            }
       }

   ''' <summary>
   ''' Gets the ping commandline arguments.
   ''' </summary>
   Private ReadOnly Property PingArguments As String
       Get
           Return String.Format("ping.exe -t ""{0}.{1}.{2}.{3}""",
                               TextBox1.Text, TextBox2.Text,
                               TextBox3.Text, TextBox4.Text)
       End Get
   End Property

   Private Sub btnSend_Click(ByVal sender As Object, ByVal e As EventArgs) _
   Handles btnsend.Click

       Me.StartTask()

   End Sub

   Private Sub CMDAutomate()

       With Me.cmdProcess

           .StartInfo.Arguments = String.Format("/C ""{0}""", Me.PingArguments)
           .Start()
           .BeginOutputReadLine()
           .BeginErrorReadLine()
           .WaitForExit(Integer.MaxValue)

       End With

   End Sub

   ''' <summary>
   ''' Occurs when an application writes to its redirected <see cref="System.Diagnostics.Process.StandardOutput"/> stream.
   ''' Occurs when an application writes to its redirected <see cref="System.Diagnostics.Process.StandardError"/>  stream.
   ''' </summary>
   Private Sub cmdProcess_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs) _
   Handles cmdProcess.OutputDataReceived,
           cmdProcess.ErrorDataReceived

       Select Case txtresults.InvokeRequired

           Case True
               txtresults.Invoke(Sub() txtresults.AppendText("" & e.Data))
               txtresults.Invoke(Sub() txtresults.AppendText(Environment.NewLine))

           Case Else
               txtresults.AppendText(e.Data)
               txtresults.AppendText(Environment.NewLine)

       End Select

#If DEBUG Then
       ' Debug.WriteLine(e.Data)
#End If

   End Sub

   ''' <summary>
   ''' Occurs when a <see cref="System.Diagnostics.Process"/> exits.
   ''' </summary>
   Private Sub cmdProcess_Exited(ByVal sender As Object, ByVal e As EventArgs) _
   Handles cmdProcess.Exited

       Debug.WriteLine(String.Format("cmdProcess has exited with exit code: {0}",
                                     DirectCast(sender, Process).ExitCode))

   End Sub

   Private Sub LinkLabel1_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) _
   Handles LinkLabel1.LinkClicked

       ' limpio el texto de cada textbox.
       For Each tb As TextBox In Me.Controls.OfType(Of TextBox)()
           tb.Clear()
       Next tb

       ' cancelo la tarea en segundo plano.
       Me.CancelTask()

   End Sub

   Private Sub StartTask()

       Me.cmdTask = Task.Factory.StartNew(AddressOf CMDAutomate)
       Me.cmdTaskCTS = New Threading.CancellationTokenSource
       Me.cmdTaskCT = cmdTaskCTS.Token

   End Sub

   Private Sub CancelTask()

       ' Si el proceso no se ha detenido...
       If Not Me.cmdProcess.HasExited Then

           With Me.cmdProcess
               ' cancelo la lectura de los outputs.
               .CancelOutputRead()
               .CancelErrorRead()
               .Kill() ' mato el proceso (cmd.exe)
           End With

           ' Cancelo la tarea en segundo plano.
           Me.cmdTaskCTS.Cancel()
           ' Espero a que la tarea se haya cancelado.
           Me.cmdTask.Wait()

       End If

   End Sub

End Class

【问题讨论】:

标签: .net vb.net multithreading asynchronous process


【解决方案1】:

从我通过阅读本文所知道的情况来看,以及我对异步任务的有限经验,这可能与在任务中调用 .WaitForExit 的事实有关,就在开始之后。 这就是 Process.Kill 上的 MSDN 页面关于使用 Kill 和 WaitForExit 的说法: “Kill方法异步执行,调用Kill方法后,调用WaitForExit方法等待进程退出,或者查看HasExited属性判断进程是否退出。”

在这种情况下,WaitForExit 在 Kill 之前被调用,只有在任务被取消时才会调用。所以只有 WaitForExit(Int32) 有效,因为它只会等待一定的时间,而不是无限期地等待(因为它会在这里)。

请参阅有关 WaitForExit 的 MSDN 页面:http://msdn.microsoft.com/en-us/library/system.diagnostics.process.waitforexit%28v=vs.110%29.aspx

http://msdn.microsoft.com/en-us/library/fb4aw7b8%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1

无论如何,我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-03
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多