Inter Thread communication in Python

Inter Thread communication in Python with Examples

In this article, I am going to discuss Inter Thread communication in Python with examples. Please read our previous article where we discussed Synchronization in Python. As part of this article, we are going to discuss the following pointers in detail.

  1. What is Inter Thread communication in Python?
  2. Inter Thread communication by using Event Objects
  3. Inter Thread communication by using Condition Object
  4. Inter Thread communication by using Queue in python
  5. Types of Queues in Python
  6. FIFO Queue in Python
  7. LIFO Queue in Python
  8. Priority Queue in Python
What is Inter Thread communication in Python?

Sometimes one thread may be required to communicate to another thread depending on the requirement. This is called inter thread communication. In Python, we can implement inter thread communication by using the following ways:

  1. Event
  2. Condition
  3. Queue
Inter Thread communication by using Event Objects

Event object is the simplest communication mechanism between the threads. One thread signals an event and other threads wait for it. We need to create an Event object as follows

event = threading.Event()

Event manages some internal flags which can be set or cleared using the methods on event object

set():

When we call for this method an internal flag will become True and it represents a GREEN signal for all waiting threads.

event.set()

clear():

When we call for this method an internal flag value will become False and it represents a RED signal for all waiting threads.

event.clear()

isSet():

This method can be used to check whether the event is set or not.

event.isSet()

wait() or wait(seconds):

This method can be used to make a thread wait until an event is set.

event.wait()

Program: Inter Thread communication by using Event Objects in python (demo26.py)
from threading import *
import time

def traffic_police():
   while True:
       time.sleep(5)
       print("Traffic Police Giving GREEN Signal")
       event.set()
       time.sleep(10)
       print("Traffic Police Giving RED Signal")
       event.clear()

def driver():
   num=0
   while True:
       print("Drivers waiting for GREEN Signal")
       event.wait()
       print("Traffic Signal is GREEN...Vehicles can move")
       while event.isSet():
           num=num+1
           print("Vehicle No:", num," Crossing the Signal")
           time.sleep(2)
       print("Traffic Signal is RED...Drivers have to wait")

event=Event()
t1=Thread(target=traffic_police)
t2=Thread(target=driver)
t1.start()
t2.start()

Output:

Inter Thread communication by using Event Objects in python

In the above program driver thread has to wait until Trafficpolice thread sets the event. i.e until a green signal is given. Once the Traffic police thread sets an event (giving GREEN signal), vehicles can cross the signal. Again, when the traffic police thread clears the event (giving RED Signal) then the driver thread has to wait.

The traffic police thread sets the event for a period of 10 seconds before clearing it. After clearing the event it again sets it after a period of 5 seconds. The driver thread will be executed in that period of 10 seconds, event set period, and waits for the event to be set in the event clear period. Here, the event object is communicating between both the threads for the expected execution of the code.

The above program will never stop because the condition in the while loop is always True. You need to do Ctrl+c to stop the execution

Inter Thread communication by using Condition Object:

Condition is the more advanced version of Event object for inter thread communication. A Condition object can be created as follows

condition = threading.Condition()

Condition object allows one or more threads to wait until notified by another thread. Condition is always associated with a lock (ReentrantLock). A condition object has acquire() and release() methods that call the corresponding methods of the associated lock.

acquire():

This method is used to acquire the condition object. i.e thread acquiring the internal lock.

condition.acquire()

release():

This method is used to release the condition object i.e thread releases internal lock

condition.release()

wait()|wait(time):

This method is used to wait until getting notification or until the mentioned time expires

condition.wait()

notify():

This method is used to give notification for one waiting thread

condition.notify()

notifyAll():

This method is used to give notification for all waiting threads

condition.notifyAll()

Let’s consider the following use case where there are two threads, a producer thread and a consumer thread,

Producer Thread:

The producer thread needs to acquire the Condition object before producing items and should notify the remaining thread (in our case consumer thread) about it.

  1. Acquire the condition object i.e lock (Step 1.1)
  2. Produce the item (Step 1.2)
  3. Add the item to the resource (Step 1.3)
  4. Notify the other threads about it (Step 1.4)
  5. Release the condition object i.e lock (Step 1.5)
Consumer Thread:

The consumer thread must acquire the condition and then have to wait for the notification from the other thread(in our case producer thread).

  1. Acquire the condition object i.e lock (Step 2.1)
  2. Wait for the notification (Step 2.2)
  3. Use or consume the items (Step 2.3)
  4. Release the condition object i.e lock (Step 2.4)
Program: Inter Thread communication by using Condition Objects (demo27.py)
from threading import *
import time
import random

items=[]
def produce(c):
   while True:
       c.acquire() #Step 1.1
       item=random.randint(1,10) #Step 1.2
       print("Producer Producing Item:", item)
       items.append(item) #Step 1.3
       print("Producer giving Notification")
       c.notify() #Step 1.4
       c.release() #Step 1.5
       time.sleep(5)

def consume(c):
   while True:
       c.acquire() #Step 2.1
       print("Consumer waiting for update")
       c.wait() #Step 2.2
       print("Consumer consumed the item", items.pop()) #Step 2.3
       c.release() #Step 2.4
       time.sleep(5)

c=Condition()
t1=Thread(target=consume, args=(c,))
t2=Thread(target=produce, args=(c,))
t1.start()
t2.start()

Output:

Inter Thread communication by using Condition Objects

The above program will never stop because the condition in the while loop is always True. You need to do Ctrl+c to stop the execution

Inter Thread communication by using Queue in python:

Queues Concept is the most enhanced Mechanism for inter thread communication and to share data between threads. Queue internally has Condition functionality which inturn includes the Lock functionality. Hence whenever we are using Queue we are not required to worry about Synchronization.

If we want to use Queues we should import the queue module. import queue

We can create Queue object as: q = queue.Queue()

Two important methods of the queue module

  1. put(): To put an item into the queue.
  2. get(): To remove and return an item from the queue.
Lets understand how this works with the previous use case of producer and consumer threads

Producer Thread can use the put() method to insert data in the queue. Whenever the producer method calls the put method, internally, first it will acquire the lock and then insert the data into the queue and then release the lock automatically. The put method also checks whether the queue is full or not and if queue is full then the Producer thread will enter into the waiting state by calling wait() method internally.

Consumer Thread can use the get() method to remove and get data from the queue. Whenever the consumer method calls the get method, internally, first it will acquire the lock and then get/remove the data from the queue and then release the lock automatically. If the queue is empty then the consumer thread will enter into the waiting state by calling wait() method internally. Once the queue is updated with data then the thread will be notified automatically.

Program: Inter Thread communication by using Queue in python (demo28.py)
from threading import *
import time
import random
import queue

items=[]
def produce(c):
   while True:
       item=random.randint(1,10) #Step 1.2
       print("Producer Producing Item:", item)
       q.put(item)
       print("Producer giving Notification")
       time.sleep(5)

def consume(c):
   while True:
       print("Consumer waiting for update")
       print("Consumer consumed the item", q.get())
       time.sleep(5)

q=queue.Queue()
t1=Thread(target=consume, args=(q,))
t2=Thread(target=produce, args=(q,))
t1.start()
t2.start()

Output:

Inter Thread communication by using Queue in python

The above program will never stop because the condition in the while loop is always True. You need to do Ctrl+c to stop the execution

Types of Queues in Python

Python supports 3 Types of Queues:

  1. FIFO Queue
  2. LIFO Queue
  3. Priority Queue
FIFO Queue in Python:

This is the default behavior of the queue. The order in which we get the items from the queue, is the order in which the items are put(FIFO-First In First Out).

Program: FIFO Queue in python (demo29.py)

import queue
q=queue.Queue()
q.put(10)
q.put(5)
q.put(20)
q.put(15)
while not q.empty():
   print(q.get())

Output:

FIFO Queue in python

LIFO Queue in Python:

The order in which we get the items in the queue, is the reverse order of the items in which they are inserted (Last In First Out).

q=queue.LifoQueue()

Program: LIFO Queue in python (demo30.py)

import queue
q=queue.LifoQueue()
q.put(10)
q.put(5)
q.put(20)
q.put(15)
while not q.empty():
   print(q.get())

Output:

LIFO Queue in python

Priority Queue in Python:

This queue stores the items based on some priority and returns the items according to that priority. In order to decide that priority to save the elements in the queue, python uses some sorting mechanisms.

Program: Priority Queue in python (demo31.py)

import queue
q=queue.PriorityQueue()
q.put(10)
q.put(5)
q.put(20)
q.put(15)
while not q.empty():
   print(q.get())

Output:

Priority Queue in python

If the data is non-numeric, then the internal sorting mechanisms will be able to decide on the priority for the items. In such cases, we can associate the elements with some weights based on which priority can be decided.

Program: Priority Queue in python (demo32.py)
import queue
q=queue.PriorityQueue()
q.put((1,'Ruhan'))
q.put((3,'Sharuk'))
q.put((4,'Ajay'))
q.put((2,'Siva'))
while not q.empty():
   print(q.get()[1])

Output:

Priority Queue in python

We can see from the output that the values are popped according to the ordered which we provided. The point to be noted here is the data should be inserted in the form of tuples as shown above. Even while getting the data, we can access both the weight as well as value using indexing. i.e q.get()[0] will give the weight and 1.get()[1] will give the value.

In the next article, I am going to discuss Database Connectivity in Python with Examples. Here, in this article, I try to explain Inter Thread communication in Python with Examples. I hope you enjoy this Inter Thread communication in Python with Examples article. I would like to have your feedback. Please post your feedback, question, or comments about this article.

Leave a Reply

Your email address will not be published.