How can you execute threads A, B, and C in a specific sequence using multithreading?
There are several ways to execute threads A, B, and C in a specific sequence using multithreading. Here are a few common approaches:
join()
methodThis method involves starting each thread and then using the join()
method to wait for each thread to complete before starting the next one.
import threading
def task_a():
print("Executing Task A")
def task_b():
print("Executing Task B")
def task_c():
print("Executing Task C")
thread_a = threading.Thread(target=task_a)
thread_b = threading.Thread(target=task_b)
thread_c = threading.Thread(target=task_c)
thread_a.start()
thread_a.join() # Wait for thread_a to complete
thread_b.start()
thread_b.join() # Wait for thread_b to complete
thread_c.start()
thread_c.join() # Wait for thread_c to complete
print("All tasks completed in sequence.")
Explanation:
threading.Thread()
and started with start()
.join()
method ensures that the main thread waits for the respective thread to finish its execution before proceeding to the next thread.Semaphores can be used to control the order of execution. Each thread waits on a semaphore before starting, and signals the next thread when it finishes.
import threading
import time
class SemaphoreController:
def __init__(self):
self.sema_a = threading.Semaphore(1) # Initially unlocked
self.sema_b = threading.Semaphore(0) # Initially locked
self.sema_c = threading.Semaphore(0) # Initially locked
def task_a(self):
with self.sema_a:
print("Executing Task A")
time.sleep(1)
self.sema_b.release() # Signal to task_b to start
def task_b(self):
with self.sema_b:
print("Executing Task B")
time.sleep(1)
self.sema_c.release() # Signal to task_c to start
def task_c(self):
with self.sema_c:
print("Executing Task C")
time.sleep(1)
if __name__ == "__main__":
controller = SemaphoreController()
thread_a = threading.Thread(target=controller.task_a)
thread_b = threading.Thread(target=controller.task_b)
thread_c = threading.Thread(target=controller.task_c)
thread_a.start()
thread_b.start()
thread_c.start()
thread_a.join()
thread_b.join()
thread_c.join()
print("All tasks completed in sequence.")
Explanation:
SemaphoreController
manages the semaphores.sema_a
is initialized with a value of 1, allowing task_a
to start immediately.sema_b
and sema_c
are initialized with a value of 0, so task_b
and task_c
wait until they are released.with self.sema_x:
), executes, and then releases the next semaphore.time.sleep(1)
is added to simulate work being done.Locks can also be used, similar to semaphores, but they are binary (locked/unlocked).
import threading
import time
class LockController:
def __init__(self):
self.lock_a = threading.Lock()
self.lock_b = threading.Lock()
self.lock_c = threading.Lock()
self.lock_b.acquire() # Initially locked
self.lock_c.acquire() # Initially locked
def task_a(self):
with self.lock_a:
print("Executing Task A")
time.sleep(1)
self.lock_b.release() # Signal to task_b to start
def task_b(self):
with self.lock_b:
print("Executing Task B")
time.sleep(1)
self.lock_c.release() # Signal to task_c to start
def task_c(self):
with self.lock_c:
print("Executing Task C")
time.sleep(1)
if __name__ == "__main__":
controller = LockController()
thread_a = threading.Thread(target=controller.task_a)
thread_b = threading.Thread(target=controller.task_b)
thread_c = threading.Thread(target=controller.task_c)
thread_a.start()
thread_b.start()
thread_c.start()
thread_a.join()
thread_b.join()
thread_c.join()
print("All tasks completed in sequence.")
Explanation:
LockController
manages the locks.lock_a
is initially unlocked, allowing task_a
to start.lock_b
and lock_c
are initially acquired (locked), so task_b
and task_c
wait until they are released.with self.lock_x:
), executes, and then releases the next lock.time.sleep(1)
is added to simulate work being done.Condition objects can also be used to control the sequence of thread execution. Threads wait on a condition and are notified by other threads to proceed.
import threading
import time
class ConditionController:
def __init__(self):
self.condition = threading.Condition()
self.task_order = 0 # 0: A, 1: B, 2: C
def task_a(self):
with self.condition:
while self.task_order != 0:
self.condition.wait()
print("Executing Task A")
time.sleep(1)
self.task_order = 1
self.condition.notify_all()
def task_b(self):
with self.condition:
while self.task_order != 1:
self.condition.wait()
print("Executing Task B")
time.sleep(1)
self.task_order = 2
self.condition.notify_all()
def task_c(self):
with self.condition:
while self.task_order != 2:
self.condition.wait()
print("Executing Task C")
time.sleep(1)
self.task_order = 3 # Mark as completed
self.condition.notify_all()
if __name__ == "__main__":
controller = ConditionController()
thread_a = threading.Thread(target=controller.task_a)
thread_b = threading.Thread(target=controller.task_b)
thread_c = threading.Thread(target=controller.task_c)
thread_a.start()
thread_b.start()
thread_c.start()
thread_a.join()
thread_b.join()
thread_c.join()
print("All tasks completed in sequence.")
Explanation:
ConditionController
manages the condition object and the task order.with self.condition:
).while
loop checks if it is the task's turn to execute. If not, it waits.task_order
, and notifies all waiting threads.time.sleep(1)
is added to simulate work being done.Each of these methods ensures that threads A, B, and C execute in the specified sequence, with thread synchronization mechanisms preventing race conditions and ensuring orderly execution.