thread termination
multithreading
programming
thread management
concurrency

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.

Browse interview questions

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:

python
1import threading
2import time
3
4stop_event = threading.Event()
5
6def worker():
7    while not stop_event.is_set():
8        print("working...")
9        time.sleep(0.5)
10    print("worker exiting cleanly")
11
12thread = threading.Thread(target=worker)
13thread.start()
14
15time.sleep(2)
16stop_event.set()
17thread.join()
18print("main finished")

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:

python
1import threading
2import time
3
4def worker():
5    while True:
6        print("daemon working...")
7        time.sleep(0.5)
8
9thread = threading.Thread(target=worker, daemon=True)
10thread.start()
11
12time.sleep(2)
13print("main finished")

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
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track 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.

Browse interview questions

All Rights Reserved.