How to terminate a thread when main program ends?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
If you want a thread to stop when the main program ends, the right solution depends on whether you want a clean shutdown or an automatic abrupt exit. Those are not the same thing.
In most programs, the best approach is cooperative shutdown: signal the worker thread to stop, then join it. Daemon threads exist for the cases where you explicitly do not want the thread to keep the process alive, but that convenience comes with tradeoffs.
Prefer Cooperative Shutdown
The safest pattern is to give the worker thread a stop signal that it checks regularly. In Python, a threading.Event works well:
This solves the real problem cleanly:
- the worker gets a chance to release resources
- the main thread controls shutdown timing
- the program ends predictably
That is almost always better than forcing termination.
What Daemon Threads Actually Do
If the thread should not block program exit, mark it as a daemon:
When the main thread finishes and no non-daemon threads remain, the process exits and the daemon thread is stopped by process termination.
That behavior is convenient for background helpers that do not own important state. It is not a graceful shutdown mechanism. The daemon thread may stop in the middle of a file write, network call, or partially updated in-memory structure.
Do Not Rely on "Killing" Threads
Many environments either do not support forcibly killing threads safely or discourage it heavily. The reason is simple: a thread may be holding locks, updating shared state, or using external resources when you stop it.
If you terminate it abruptly, you can leave the application in a corrupted or deadlocked state.
That is why the better mental model is:
- ask the thread to stop
- let it reach a safe exit point
- wait for it with
join()
This is true across most mainstream threading environments, even though the exact API names differ.
Structure the Worker So It Can Stop
The stop signal approach only works if the worker periodically checks for shutdown. A worker blocked forever on a long operation cannot respond promptly.
That means long-running loops should be designed to:
- poll a stop flag or event
- use timeouts on blocking calls
- break work into smaller steps when possible
For example, a network loop that waits indefinitely may need socket timeouts so it can wake up, see the shutdown request, and exit.
The termination problem is often really a worker-design problem.
When Daemon Threads Are Appropriate
Daemon threads are reasonable when all of the following are true:
- losing the work is acceptable
- the thread does not own critical data
- you do not need a cleanup guarantee
- you only want helper behavior during normal process lifetime
Examples might include lightweight metrics sampling or cache warming. Even then, explicit shutdown is usually clearer in production services.
Common Pitfalls
- Expecting daemon threads to perform guaranteed cleanup when the program exits.
- Building a worker loop that never checks for a stop condition.
- Confusing "the process can exit" with "the thread shut down safely."
- Forcing thread termination while it holds locks or external resources.
- Forgetting to
join()a non-daemon thread, which can make the process appear hung at shutdown.
Summary
- Cooperative shutdown is usually the correct way to stop threads when the main program ends.
- Use a stop flag or event, then call
join()for a clean exit. - Daemon threads only mean the process is allowed to exit without waiting for them.
- Daemon threads are convenient but not graceful.
- If a thread must release resources correctly, design it to stop cooperatively instead of trying to kill it.
Related reading
- How to test an asynchronous JavaScript function Promises, Jasmine, PhantomJS
- How to throw an exception from callback in WCF Async using IAsyncResult
- How to timeout a thread
- How to timeout a thread
- How to trace async/await errors in node.js?
- How to track requests and completion status in async systems?
- How to unit test asynchronous APIs?
- How to update local tags to match remote?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free 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.