Threads and mutex used case.
Given 2 threads even prints even nos till 10, and odd print odd nos till 10, how you run them so that they will print below sequence : 1->2->3->4->5->6->7->8->9->10
To ensure that the threads print the sequence 1->2->3->4->5->6->7->8->9->10 in the correct order, we can use a synchronization mechanism called a “mutex” (short for mutual exclusion).
Here’s the code in C++:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_even() {
for(int i=2; i<=10; i+=2) {
mtx.lock();
std::cout << i << std::endl;
mtx.unlock();
}
}
void print_odd() {
for(int i=1; i<=9; i+=2) {
mtx.lock();
std::cout << i << std::endl;
mtx.unlock();
}
}
int main() {
std::thread t1(print_even);
std::thread t2(print_odd);
t1.join();
t2.join();
return 0;
}
This code uses the std::mutex
class from the C++ standard library to implement the mutual exclusion mechanism. The print_even()
and print_odd()
functions are defined similarly to the Python code, with a loop that prints the even or odd numbers, respectively. Before each print statement, the function acquires the mutex using mtx.lock()
, and releases it afterwards using mtx.unlock()
.
In the main function, we create two threads t1
and t2
using the std::thread
class, passing in the print_even()
and print_odd()
functions, respectively. We then call t1.join()
and t2.join()
to wait for the threads to complete before exiting the program.
A mutex (short for mutual exclusion) is a synchronization mechanism that is used to prevent multiple threads from accessing shared resources (such as variables or code segments) simultaneously. When a thread acquires a mutex, it gains exclusive access to the critical section of code that is protected by the mutex. This ensures that no other thread can access the critical section until the mutex is released by the owning thread.
In the code provided earlier, we use a mutex to ensure that the even and odd threads alternate printing the numbers in sequence, without any overlap or race conditions. Specifically, we use a single mutex to protect the critical section (i.e., the print statement) in both the print_even()
and print_odd()
functions. When a thread wants to access the critical section, it first acquires the mutex using mutex.acquire()
(or mtx.lock()
in the C++ code), which blocks the thread if the mutex is already locked by another thread. Once the mutex is acquired, the thread can execute the critical section, in this case printing a number to the console. After completing the critical section, the thread releases the mutex using mutex.release()
(or mtx.unlock()
), which allows other threads to acquire the mutex and access the critical section in turn.
Without the use of a mutex, there is a risk of race conditions occurring between the two threads. For example, if both threads try to print a number at the same time, the output may be interleaved in an unpredictable way, resulting in an incorrect sequence of numbers being printed. The use of a mutex ensures that only one thread can access the critical section at a time, preventing such race conditions and ensuring correct synchronization between the threads.
We use the join()
method to wait for the child threads to complete before exiting the main thread. When a thread is started using the std::thread
(in C++) or threading.Thread()
(in Python) constructors, a new thread of execution is created and runs concurrently with the main thread. However, if the main thread exits before the child threads complete, the child threads may be terminated prematurely and their work may not be completed correctly.
To avoid this problem, we call the join()
method on each child thread after starting them. This causes the main thread to block until the child thread completes and returns control to the main thread. Only after all child threads have completed and the main thread has joined them can the program safely exit.
In the code provided earlier, we call t1.join()
and t2.join()
to wait for the child threads to complete. This ensures that the even and odd threads have finished printing all the numbers in the correct order before the program exits. Without the use of join()
, the program may exit prematurely, resulting in incomplete or incorrect output.