Nearby lessons

146 of 159

Python - Threading Quick Revision

📌 What You Will Learn
  • Revise all threading concepts from the chapter
  • Recall thread creation and management methods
  • Recall synchronization mechanisms and when to use each
  • Recall inter thread communication options
  • Prepare for interview and examination questions

Python Threading Complete Summary

This section provides a quick revision of all important concepts covered in Python Multi Threading.

We have learned about:

  • Multi Tasking
  • Process Based Multi Tasking
  • Thread Based Multi Tasking
  • Applications of Multi Threading
  • Python threading module
  • Main Thread
  • Creating Threads
  • Thread methods
  • Thread information
  • Daemon Threads
  • Synchronization
  • Lock
  • RLock
  • Semaphore
  • BoundedSemaphore
  • Inter Thread Communication
  • Event
  • Condition
  • Queue

1. What is Multi Tasking?

Multi Tasking means executing several tasks simultaneously.

There are two types of Multi Tasking:

  1. Process Based Multi Tasking
  2. Thread Based Multi Tasking
                 Multi Tasking
                      │
            ┌─────────┴─────────┐
            │                   │
            ▼                   ▼
     Process Based         Thread Based
      Multi Tasking         Multi Tasking

Simple Definition:

Executing several tasks simultaneously is called Multi Tasking.

2. Process Based Multi Tasking

In Process Based Multi Tasking, every task runs as a separate process.

It is best suitable at the Operating System level.

Examples:

  • Editing a Python program
  • Listening to MP3 songs
  • Downloading a file

All these tasks execute independently.

Operating System
      │
      ├── Process 1 → Edit Python Program
      │
      ├── Process 2 → Play MP3 Song
      │
      └── Process 3 → Download File

3. Thread Based Multi Tasking

In Thread Based Multi Tasking, multiple independent parts of the same program execute simultaneously.

Each independent part is called a Thread.

Thread Based Multi Tasking is best suitable at the program level.

              One Program
                  │
        ┌─────────┼─────────┐
        │         │         │
        ▼         ▼         ▼
     Thread-1  Thread-2  Thread-3

Simple Definition:

A Thread is an independent part of the same program.

Process Based vs Thread Based Multi Tasking

Process Based Thread Based
Each task is a separate process. Each task is an independent part of the same program.
Best suitable at OS level. Best suitable at program level.
Processes execute independently. Multiple Threads belong to the same program.

4. Applications of Multi Threading

Important applications of Multi Threading include:

  • Multimedia Graphics
  • Animations
  • Video Games
  • Web Servers
  • Application Servers
Multi Threading
      │
      ├── Multimedia Graphics
      ├── Animations
      ├── Video Games
      ├── Web Servers
      └── Application Servers

5. Python Thread Module

Python provides the built-in module:

threading

to develop multi-threaded applications.

We can import it using:

import threading

or:

from threading import *

6. Main Thread

Every Python program contains one default Thread.

It is called:

MainThread

The Main Thread starts automatically when the Python program starts.

Python Program Starts
        │
        ▼
    MainThread
        │
        ▼
Execute Program

7. Ways to Create Threads

Python supports three ways to create Threads:

  1. Creating a Thread without using any class
  2. Creating a Thread by extending the Thread class
  3. Using a normal class object as Thread target
Method Concept
Method 1 Create Thread with a target function
Method 2 Extend Thread and override run()
Method 3 Use a normal class method as the Thread target

Thread Creation - Quick Example

🐍Code Cell
1from threading import *
2 
3def display():
4 print("Child Thread")
5 
6t = Thread(target=display)
7t.start()
8 
9print("Main Thread")
Output
No output captured.

Thread Creation - Execution Flow

Program Starts
      │
      ▼
MainThread
      │
      ▼
Create Thread Object
      │
      ▼
t.start()
      │
      ▼
Child Thread Starts
      │
      ├──────────► display()
      │
      ▼
Main Thread Continues

The exact execution order can vary because Thread scheduling is not predictable.

8. Important Thread Methods

The important Thread methods covered in this tutorial are:

  • start()
  • run()
  • join()
Method Purpose
start() Starts the Thread
run() Contains the work performed by the Thread
join() Makes one Thread wait until another Thread completes

join() Method

The join() method makes one Thread wait until another Thread completes its execution.

t.join()

We can also specify a waiting time:

t.join(seconds)

In this case, the calling Thread waits for the specified amount of time or until the target Thread completes.

9. Thread Name Methods

Every Thread has a name.

The tutorial covers the name property.

Every Thread receives a default name, which can be changed.

t.name

t.name = "MyThread"

10. Thread Identification Number

Every Thread has a unique identification number.

It can be accessed using:

ident

Example:

t.ident

This provides the identification number associated with the Thread.

11. active_count()

active_count() returns the number of currently active Threads.

active_count()

Conceptually:

Currently Running Threads

MainThread
Thread-1
Thread-2

active_count()
      │
      ▼
      3

12. enumerate()

enumerate() returns a list containing all currently active Thread objects.

enumerate()

It can be used when we want information about all active Threads.

13. is_alive()

is_alive() checks whether a Thread is still executing.

t.is_alive()

Conceptually:

Thread Running
     │
     ▼
   True


Thread Completed
     │
     ▼
   False

Thread Information - Quick Revision

Method / Property Purpose
name Get or change Thread name
ident Get Thread identification number
active_count() Count active Threads
enumerate() Return active Thread objects
is_alive() Check whether Thread is executing

14. Daemon Threads

Daemon Threads run in the background and provide support to Non-Daemon Threads.

Example:

  • Garbage Collector

When the last Non-Daemon Thread terminates, the remaining Daemon Threads terminate automatically.

Main Thread
Non-Daemon Threads
       │
       ▼
All Complete
       │
       ▼
Remaining Daemon Threads
Terminate Automatically

15. Synchronization

Synchronization is used to avoid data inconsistency when multiple Threads access shared resources.

The synchronization techniques covered are:

  • Lock
  • RLock
  • Semaphore
Synchronization
      │
      ├── Lock
      ├── RLock
      └── Semaphore

Simple Definition:

Synchronization controls concurrent access to shared resources so that data inconsistency can be avoided.

Why Synchronization?

Without proper synchronization, multiple Threads may access the same shared resource simultaneously.

Thread-1 ─────┐
              │
              ▼
        Shared Resource
              ▲
              │
Thread-2 ─────┘

Possible Problem
      │
      ▼
Data Inconsistency

Synchronization controls access to the shared resource.

16. Lock

A Lock allows only one Thread at a time to enter the protected section.

Important methods:

acquire()
release()

Basic pattern:

l.acquire()

# Critical Section

l.release()
Thread-1
   │
   ▼
Acquire Lock
   │
   ▼
Critical Section
   │
   ▼
Release Lock
   │
   ▼
Next Waiting Thread

17. RLock

RLock means Reentrant Lock.

The same Thread can acquire an RLock multiple times.

This is useful for:

  • Recursive functions
  • Nested resource access
Same Thread
    │
    ├── acquire()
    ├── acquire()
    ├── acquire()
    │
    ▼
Allowed with RLock

The Thread must release the RLock appropriately for its acquisitions.

Lock vs RLock

Lock RLock
A Thread cannot safely acquire the same Lock again while already holding it. The owning Thread can acquire the same RLock multiple times.
Repeated acquisition by the same Thread can block it. Supports reentrant acquisition.
Suitable for basic synchronization. Useful for recursive and nested locking.

18. Semaphore

A Semaphore allows a fixed number of Threads to access a protected section simultaneously.

Example:

s = Semaphore(3)

Here, up to three Threads can acquire the Semaphore at the same time.

Semaphore(3)

Thread-1 ──► Allowed
Thread-2 ──► Allowed
Thread-3 ──► Allowed
Thread-4 ──► Wait
Thread-5 ──► Wait

Lock vs Semaphore

Lock Semaphore
Only one Thread can acquire it at a time. A fixed number of Threads can acquire it at the same time.
Used for exclusive access. Used for limited concurrent access.

19. BoundedSemaphore

BoundedSemaphore is similar to Semaphore.

The important difference is that it prevents the Semaphore counter from being released beyond its initial bound.

The tutorial demonstrates this with extra release() calls.

s = BoundedSemaphore(2)

s.acquire()
s.acquire()

s.release()
s.release()

# Extra release
s.release()

This results in:

ValueError: Semaphore released too many times

This can help detect programming mistakes involving unmatched release() operations.

20. Inter Thread Communication

Sometimes multiple Threads need to communicate with each other.

This concept is called Inter Thread Communication.

Python mechanisms covered in the tutorial are:

  • Event
  • Condition
  • Queue
        Inter Thread Communication
                   │
         ┌─────────┼─────────┐
         │         │         │
         ▼         ▼         ▼
       Event   Condition    Queue

Producer-Consumer Concept

A common example of Inter Thread Communication is the Producer–Consumer model.

Producer Thread
      │
      ▼
Produce Item
      │
      ▼
Communicate
      │
      ▼
Consumer Thread
      │
      ▼
Consume Item

The Producer creates new items, while the Consumer waits for and consumes those items.

21. Event

An Event provides a simple mechanism for communication between Threads.

Important methods covered in the tutorial:

  • set()
  • clear()
  • is_set()
  • wait()
Method Purpose
set() Sets the internal flag to True
clear() Sets the internal flag to False
is_set() Checks whether the Event is set
wait() Waits until the Event becomes set

Event - Quick Flow

Consumer
   │
   ▼
event.wait()
   │
   ▼
Waiting
   │
   │
   │ Producer
   │
   ▼
event.set()
   │
   ▼
Consumer Continues

22. Condition

Condition provides a more advanced communication mechanism.

Important methods:

  • acquire()
  • release()
  • wait()
  • notify()
  • notify_all()
Method Purpose
acquire() Acquire the associated Lock
release() Release the associated Lock
wait() Wait for notification
notify() Notify one waiting Thread
notify_all() Notify all waiting Threads

Condition - Producer Consumer Flow

Consumer
   │
   ▼
acquire()
   │
   ▼
wait()
   │
   ▼
Waiting
   ▲
   │
   │ notify()
   │
Producer
   │
   ▼
acquire()
   │
   ▼
Produce Item
   │
   ▼
notify()
   │
   ▼
release()

The Consumer generally waits, while the Producer performs the update and sends the notification.

23. Queue

Queue provides an easy and powerful mechanism for sharing data between Threads.

The important methods are:

  • put()
  • get()
Producer
   │
   ▼
q.put(item)
   │
   ▼
 Queue
   │
   ▼
q.get()
   │
   ▼
Consumer

Queue automatically handles:

  • Locking
  • Waiting
  • Notification

Queue Behaviour

If a bounded Queue is full, a blocking Producer waits until space becomes available.

If the Queue is empty, a blocking Consumer waits until an item becomes available.

Queue Full
    │
    ▼
Producer Waits


Queue Empty
    │
    ▼
Consumer Waits

This synchronization is handled automatically by Queue.

Event vs Condition vs Queue

Event Condition Queue
Simple communication mechanism More advanced communication mechanism Most enhanced mechanism covered in the tutorial
Works using an internal flag Uses waiting and notification with locking Designed for synchronized data sharing
set(), clear(), wait() wait(), notify(), etc. put(), get()
Useful for signaling Useful when manual control is required Very convenient for Producer–Consumer communication

Complete Threading Concept Flow

Python Multi Threading
        │
        ├── Multi Tasking
        │      ├── Process Based
        │      └── Thread Based
        │
        ├── threading Module
        │
        ├── MainThread
        │
        ├── Thread Creation
        │      ├── Target Function
        │      ├── Extend Thread
        │      └── Normal Class Method
        │
        ├── Thread Operations
        │      ├── start()
        │      ├── run()
        │      └── join()
        │
        ├── Thread Information
        │      ├── name
        │      ├── ident
        │      ├── active_count()
        │      ├── enumerate()
        │      └── is_alive()
        │
        ├── Daemon Threads
        │
        ├── Synchronization
        │      ├── Lock
        │      ├── RLock
        │      ├── Semaphore
        │      └── BoundedSemaphore
        │
        └── Inter Thread Communication
               ├── Event
               ├── Condition
               └── Queue

Complete Revision Table

Topic Important Points
Multi Tasking Process Based and Thread Based
Thread Module threading
Main Thread MainThread
Thread Creation Three ways
Main Methods start(), run(), join()
Thread Information name, ident, active_count(), enumerate(), is_alive()
Daemon Thread Background support Thread
Synchronization Lock, RLock, Semaphore
Lock One Thread at a time
RLock Same owning Thread can acquire multiple times
Semaphore Fixed number of Threads can access simultaneously
BoundedSemaphore Prevents releases beyond the initial bound
Inter Thread Communication Event, Condition, Queue
Event Methods set(), clear(), is_set(), wait()
Condition Methods acquire(), release(), wait(), notify(), notify_all()
Queue Methods put(), get()

Summary

  • Multi Tasking means executing several tasks simultaneously.
  • Multi Tasking can be Process Based or Thread Based.
  • A Thread is an independent part of the same program.
  • Python provides the threading module for Multi Threading.
  • Every Python program starts with a default MainThread.
  • Python supports three approaches to creating Threads covered in this tutorial.
  • start() starts a Thread.
  • run() contains the Thread's job when working with the Thread class.
  • join() can make one Thread wait for another.
  • Thread information can be obtained using names, ident, active_count(), enumerate(), and Thread-status methods.
  • Daemon Threads provide background support to Non-Daemon Threads.
  • Synchronization is used to protect shared resources from data inconsistency.
  • Lock permits one Thread at a time.
  • RLock supports repeated acquisition by the owning Thread.
  • Semaphore permits a fixed number of Threads simultaneously.
  • BoundedSemaphore can detect excessive releases.
  • Event, Condition, and Queue are used for Inter Thread Communication.
  • Event provides simple signaling.
  • Condition provides controlled waiting and notification.
  • Queue simplifies synchronized data sharing between Producer and Consumer Threads.

Important Notes

  1. The threading module is used to develop multi-threaded Python applications.
  2. Every Python program contains a Main Thread.
  3. The execution order of multiple Threads is generally not predictable.
  4. start() should be used to start a Thread.
  5. join() is used when one Thread must wait for another Thread.
  6. ident provides the Thread identification number.
  7. active_count() returns the number of active Threads.
  8. enumerate() returns active Thread objects.
  9. Daemon Threads work in the background to support Non-Daemon Threads.
  10. Synchronization is important when multiple Threads access shared resources.
  11. Lock provides exclusive access to one Thread at a time.
  12. RLock is useful when the owning Thread needs to acquire the same lock repeatedly.
  13. Semaphore allows a fixed number of Threads to enter simultaneously.
  14. BoundedSemaphore helps identify incorrect extra release() operations.
  15. Event is the simplest Inter Thread Communication mechanism covered in this tutorial.
  16. Condition provides more control over waiting and notification.
  17. Queue provides automatic synchronization for Producer–Consumer data sharing.
  18. The Producer generally uses put() with Queue.
  19. The Consumer generally uses get() with Queue.
  20. Queue automatically handles locking, waiting, and notification.
📝 Key Takeaways
  • Multi tasking is the base of multi threading
  • Threads are created via Thread(target=...) and started with start()
  • Lock, RLock, and Semaphore provide synchronization
  • Event, Condition, and Queue enable inter thread communication

🧠 Test Your Knowledge

20 Questions
Progress: 0 / 20