I have this weird problem. I need to invoke a process from within a background worker
Private Shared _process As Process
Private Shared _StartInfo As ProcessStartInfo
Private WithEvents _bwConvertMedia As New BackgroundWorker
Here is the work in DoWorkAsync
Private Async Sub _bwConvertMedia_DoWorkAsync(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles _bwConvertMedia.DoWork
For AI = 1 To 100
_StartInfo = New ProcessStartInfo(".\mycmd.exe", "-1")
_StartInfo.RedirectStandardOutput = True
_StartInfo.UseShellExecute = False
_StartInfo.CreateNoWindow = True
_StartInfo.RedirectStandardError = True
_process = New Process() With {.EnableRaisingEvents = True, .StartInfo = _StartInfo}
AddHandler _process.OutputDataReceived, AddressOf OutputHandler
AddHandler _process.ErrorDataReceived, AddressOf ErrorHandler
AddHandler _process.Exited, AddressOf Exited
Try
aSuccess = Await AwaitProcess()
Catch ex As Exception
End Try
_bwConvertMedia.ReportProgress(ai)
Next
And here the
Private Shared Async Function AwaitProcess() As Task(Of Integer)
_tcs = New TaskCompletionSource(Of Integer)
_status.Converting = True
_Error.Clear()
_process.Start()
_process.BeginErrorReadLine()
_process.BeginOutputReadLine()
Return Await _tcs.Task
End Function
The issue is that when the Await _tcs.Task is executed the _bwConvertMedia RunWorkerCompleted procedure is executed so when I do call the _bwConvertMedia.ReportProgress(ai)
I get an error that the worker is already finished.
Why is that? can you help me?
What happens is
- DoWork - iteration 1
- at wait process 1
- RunWorkerComplete
- DoWork iteration 2-100
The correct behavior is that the background worker invokes 100 times the process and THEN it finishes the execution and calls the RunWorkerCompleted
I made some modifications to the code I previously linked and here are two examples of a sequential non-blocking Async/Await procedure and a non-blocking Parallel procedure using
Task.Factory
.To synchronize the running tasks/threads with the UI, I used in the first case the
.SynchronizingObject
of the processes and in the second the TaskScheduler methodTaskScheduler.FromCurrentSynchronizationContext()
.The output from
Tracert.exe
is passed to two TextBoxes. In the parallel example, I inserted a delay of 1 second between Tasks, to see how the two TextBoxes are updated.The Async/Await example can be modified to work differently, since you don't need to wait for a task to complete to start another.
The
ProcessStartInfo
andProcess
objects are added to a Pool using aList(Of ProcessStartInfo)
and aList(Of Process)
.Sequential Async/Await
Parallel processes using Task.Fatory
Define a Scheduler and associate it with the current context