BACKGROUND:
I'm writing a program that opens an interactive console application, listens to STDOUT/STDERR, and sends commands to this interactive session. At the end it will issue an exit command and the process normally goes away. If the user clicks the close button I call dispose on the class which issues the exit command and then attempts to force close the session before the program terminates. I notice that after a day of testing I have a bunch of orphaned processes still running. They build up and never quit. Obviously, I've made a terrible mistake.
QUESTION:
How do I ensure that my console processes are fully dead before my application terminates?
MY DISPOSE METHOD:
Protected Overridable Async Sub Dispose(disposing As Boolean)
If _disposed Then Return
If disposing Then
_handle.Dispose()
' Free any other managed objects here.
'
If IsConnected Then Await ClosePort().ConfigureAwait(False)
If _transmissionCancel IsNot Nothing Then _transmissionCancel.Dispose()
End If
' Free any unmanaged objects here.
'
If _consoleReader IsNot Nothing Then _consoleReader.Dispose()
If _consoleWriter IsNot Nothing Then _consoleWriter.Dispose()
If _consoleProcess IsNot Nothing Then _consoleProcess.Dispose()
_disposed = True
End Sub
NOTE: The "ClosePort" method called here features a kill and a wait:
If Not _consoleProcess.WaitForExit(SocketTimeout) Then
_consoleProcess.Kill()
_consoleProcess.WaitForExit()
End If
On a suggestion from @hans-passant; I attempted to remove the "Async" modifier from my Dispose method and synchronously wait for the task to complete before completing disposal. I made a task of my function and told it to start. This appears to work but now my program doesn't end when I click the close button. My code jumps from the ".start" to the "End Using" but then the Dispose method stops, passing control back to the UI. If I click close a second time then the dispose method fires again and my program cleanly shuts down.
I post this as an answer because it appears to have solved my original problem and it is my current answer. However, I don't want to mark this as the solution because I have to click close twice to end my program. What have I done?
I am still open to other solutions.
Protected Overridable Sub Dispose(disposing As Boolean)
If _disposed Then Return
If disposing Then
_handle.Dispose()
' Free any other managed objects here.
'
If IsConnected Then
Using holdOnAMinute As Task = Task.Run(Function() ClosePort())
holdOnAMinute.Start()
holdOnAMinute.Wait(SocketTimeout)
End Using
End If
End If
' Free any unmanaged objects here.
'
If _consoleReader IsNot Nothing Then _consoleReader.Dispose()
If _consoleWriter IsNot Nothing Then _consoleWriter.Dispose()
If _consoleProcess IsNot Nothing Then _consoleProcess.Dispose()
If _transmissionCancel IsNot Nothing Then _transmissionCancel.Dispose()
_disposed = True
End Sub