【发布时间】: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
【问题讨论】:
-
尝试设置 Process.SynchronizingObject:msdn.microsoft.com/en-us/library/…
标签: .net vb.net multithreading asynchronous process