Process.WaitForExit asynchronously
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Process.WaitForExit() blocks the current thread until the child process ends. That is fine for a console utility, but it is a poor fit for UI code, servers, and any workflow where you want the calling thread to stay responsive while the external process runs.
The modern solution: WaitForExitAsync
In current .NET versions, the simplest answer is to use WaitForExitAsync.
This avoids blocking the calling thread while still giving you a proper awaitable completion point.
Why Task.Run(() => process.WaitForExit()) is not ideal
You will sometimes see code like this:
That does make the calling code awaitable, but it still burns a thread pool thread just to sit and wait. It is usually a compatibility workaround, not the best design.
If WaitForExitAsync is available in your target framework, prefer it.
Handling output without deadlocks
A related problem is that people often wait for the process to exit before reading redirected output. That can deadlock if the child process fills its output buffer and blocks waiting for the parent to read.
A safer pattern is:
- start the process
- begin reading standard output and standard error
- await process completion
- await the read tasks
The order matters when output is redirected.
Older frameworks without WaitForExitAsync
If you target an older framework, use the Exited event with a TaskCompletionSource.
Then use it like this:
That avoids blocking a worker thread and behaves more like the built-in async API.
Cancellation and timeouts
Sometimes you do not want to wait forever. Wrap the wait in a cancellation token or timeout policy.
If your target framework does not support the token overload, use Task.WhenAny with a delay task and kill the process if it exceeds the timeout.
Dispose and sequencing considerations
Remember that a Process object owns unmanaged resources. In production code, dispose it when you are done, usually with using or await using patterns where appropriate. Also make sure you do not dispose the process before asynchronous reads and exit waiting have completed, or you can end up with incomplete output capture and confusing exceptions.
Common Pitfalls
- Wrapping synchronous waiting in
Task.Runand assuming that makes it truly asynchronous. - Redirecting output but not reading it until after the process exits.
- Forgetting
UseShellExecute = falsewhen redirecting standard output or error. - Not handling timeouts for processes that can hang indefinitely.
- Using
WaitForExit()on a UI thread and freezing the interface.
Summary
- '
Process.WaitForExit()blocks the current thread.' - In modern .NET, use
await process.WaitForExitAsync()instead. - Read redirected output asynchronously to avoid deadlocks.
- On older frameworks, use the
Exitedevent plusTaskCompletionSource. - Add cancellation or timeout handling for long-running external processes.
Related reading
- Producer-consumer with sempahores
- Producer/consumer multithreading
- Programmatically determine which Java thread holds a lock
- Promise is blocking the thread
- Produce a random number in a range using C
- Programmatically detecting Release/Debug mode .NET
- promise.all inside a forEach loop — everything firing at once
- Promises - How to make asynchronous code execute synchronous without async / await?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.