Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial programming >> Python

Mastering Inter-Thread Communication in Python: Synchronization & Data Sharing

Inter-Thread Communication refers to the process of enabling communication and synchronization between threads within a Python multi-threaded program.

Generally, threads in Python share the same memory space within a process, which allows them to exchange data and coordinate their activities through shared variables, objects, and specialized synchronization mechanisms provided by the threading module.

To facilitate inter-thread communication, the threading module provides various synchronization primitives like, Locks, Events, Conditions, and Semaphores objects. In this tutorial you will learn how to use the Event and Condition object for providing the communication between threads in a multi-threaded program.

The Event Object

An Event object manages the state of an internal flag so that threads can wait or set. Event object provides methods to control the state of this flag, allowing threads to synchronize their activities based on shared conditions.

The flag is initially false and becomes true with the set() method and reset to false with the clear() method. The wait() method blocks until the flag is true.

Following are the key methods of the Event object −

Example

The following code attempts to simulate the traffic flow being controlled by the state of traffic signal either GREEN or RED.

There are two threads in the program, targeting two different functions. The signal_state() function periodically sets and resets the event indicating change of signal from GREEN to RED.

The traffic_flow() function waits for the event to be set, and runs a loop till it remains set.

from threading import Event, Thread
import time
terminate = False
def signal_state():
 global terminate
 while not terminate:
 time.sleep(0.5)
 print("Traffic Police Giving GREEN Signal")
 event.set()
 time.sleep(1)
 print("Traffic Police Giving RED Signal")
 event.clear()
def traffic_flow():
 global terminate
 num = 0
 while num < 10 and not terminate:
 print("Waiting for GREEN Signal")
 event.wait()
 print("GREEN Signal ... Traffic can move")
 while event.is_set() and not terminate:
 num += 1
 print("Vehicle No:", num," Crossing the Signal")
 time.sleep(1)
 print("RED Signal ... Traffic has to wait")
event = Event()
t1 = Thread(target=signal_state)
t2 = Thread(target=traffic_flow)
t1.start()
t2.start()
# Terminate the threads after some time
time.sleep(5)
terminate = True
# join all threads to complete
t1.join()
t2.join()
print("Exiting Main Thread")

Output

On executing the above code you will get the following output −

Waiting for GREEN Signal
Traffic Police Giving GREEN Signal
GREEN Signal ... Traffic can move
Vehicle No: 1 Crossing the Signal
Traffic Police Giving RED Signal
RED Signal ... Traffic has to wait
Waiting for GREEN Signal
Traffic Police Giving GREEN Signal
GREEN Signal ... Traffic can move
Vehicle No: 2 Crossing the Signal
Vehicle No: 3 Crossing the Signal
Traffic Police Giving RED Signal
Traffic Police Giving GREEN Signal
Vehicle No: 4 Crossing the Signal
Traffic Police Giving RED Signal
RED Signal ... Traffic has to wait
Traffic Police Giving GREEN Signal
Traffic Police Giving RED Signal
Exiting Main Thread

The Condition Object

The Condition object in Python's threading module provides a more advanced synchronization mechanism. It allows threads to wait for a notification from another thread before proceeding. The Condition object are always associated with a lock and provide mechanisms for signaling between threads.

Following is the syntax of the threading.Condition() class −

threading.Condition(lock=None)

Below are the key methods of the Condition object −

Example

This example demonstrates a simple form of inter-thread communication using the Condition object of the Python's threading module. Here thread_a and thread_b are communicated using a Condition object, the thread_a waits until it receives a notification from thread_b. the thread_b sleeps for 2 seconds before notifying thread_a and then finishes.

from threading import Condition, Thread
import time
c = Condition()
def thread_a():
 print("Thread A started")
 with c:
 print("Thread A waiting for permission...")
 c.wait()
 print("Thread A got permission!")
 print("Thread A finished")
def thread_b():
 print("Thread B started")
 with c:
 time.sleep(2)
 print("Notifying Thread A...")
 c.notify()
 print("Thread B finished")
Thread(target=thread_a).start()
Thread(target=thread_b).start()

Output

On executing the above code you will get the following output −

Thread A started
Thread A waiting for permission...
Thread B started
Notifying Thread A...
Thread B finished
Thread A got permission!
Thread A finished

Example

Here is another code demonstrating how the Condition object is used for providing the communication between threads. In this, the thread t2 runs the taskB() function, and the thread t1 runs the taskA() function. The t1 thread acquires the condition and notifies it.

By that time, the t2 thread is in a waiting state. After the condition is released, the waiting thread proceeds to consume the random number generated by the notifying function.

from threading import Condition, Thread
import time
import random
numbers = []
def taskA(c):
 for _ in range(5):
 with c:
 num = random.randint(1, 10)
 print("Generated random number:", num)
 numbers.append(num)
 print("Notification issued")
 c.notify()
 time.sleep(0.3)
def taskB(c):
 for i in range(5):
 with c:
 print("waiting for update")
 while not numbers: 
 c.wait()
 print("Obtained random number", numbers.pop())
 time.sleep(0.3)
c = Condition()
t1 = Thread(target=taskB, args=(c,))
t2 = Thread(target=taskA, args=(c,))
t1.start()
t2.start()
t1.join()
t2.join()
print("Done")

When you execute this code, it will produce the following output −

waiting for update
Generated random number: 2
Notification issued
Obtained random number 2
Generated random number: 5
Notification issued
waiting for update
Obtained random number 5
Generated random number: 1
Notification issued
waiting for update
Obtained random number 1
Generated random number: 9
Notification issued
waiting for update
Obtained random number 9
Generated random number: 2
Notification issued
waiting for update
Obtained random number 2
Done

Python

  1. Mastering Python Decorators: Enhance Functions with Expert Techniques
  2. Master Python Regular Expressions: re.match(), re.search(), re.findall() – Practical Examples
  3. Mastering Python Dictionaries: Creation, Manipulation, and Advanced Techniques
  4. Mastering Inter-Thread Communication in Python: Synchronization & Data Sharing
  5. Python list.count(): Expert Guide with Practical Examples
  6. Efficiently Measure Python Object Memory Usage with sys.getsizeof()
  7. Python Data Classes: Streamline Data Management with Modern Syntax
  8. Python Basics Cheat Sheet: Essential Data Types, Dictionaries, Lists & Functions
  9. Master Python's String.find() Method: Syntax, Examples & Alternatives
  10. Mastering Python’s Yield: Generator vs Return – A Practical Guide