MUTEX - USE AND TECHNIQUES

MUTEX - Guard at a door

JAYDEEP SHAH -radhey04ec@gmail.com

Mutex is one of the important concept and more useful in Multi-threading environment.

A Mutex is a mutually exclusive flag. It acts as a gate keeper to a section of code allowing one thread in and blocking access to all others. This ensures that the code being controlled will only be hit by a single thread at a time. Just be sure to release the mutex when block end so new thread can enter and use critical section of code/block.

MUTEX and SEMAPHORE are not same things.... keep in mind this sentence. It looks like identical (special case = Binary SEMAPHORE), but they are not same.

Lets see what is the difference between them .

Strictly speaking, a mutex is locking mechanism used to synchronize access to a resource. Only one task (can be a thread or process based on OS abstraction) can acquire the mutex. It means there is ownership associated with mutex, and only the owner can release the lock (mutex). That means thread which lock the process then only that thread can release who locked it. sounds like Ownership.

Semaphore is Signaling mechanism . For example, if you are listening songs (assume it as one task) on your mobile and at the same time your friend calls you, an interrupt is triggered upon which an interrupt service routine (ISR) signals the call processing task to wakeup. You can unlock the SEMAPHORE from any place/section/block of entire code ,does not matter who /where SEMAPHORE release signal generating..

FAQ

1 ) What happens if a non-recursive mutex (/ OR any process lock MUTEX at leaving time of CS )is locked more than once.??

Deadlock. If a thread which had already locked a mutex, tries to lock the mutex again, it will enter into the waiting list of that mutex, which results in deadlock. It is because no other thread can unlock the mutex. An operating system implementer can exercise care in identifying the owner of mutex and return if it is already locked by same thread to prevent deadlocks.

Note : MUTEX is costly operation because one process deal with CS part of code at a time and this type of locking mechanism decrease the efficiency and speed of operation.

Note : The Mutex methods can not be called from interrupt service routines (ISR).

But , All above discussion is only useful (& valid) if all threads & processes belongs same priority level -it is nothing but MUTEX BUG in MBED OS

Date of Article 25 July 2020

Yes , if Thread lock the block of critical section using MUTEX flag and another Thread with high priority invoke at a same time then this high priority thread is capable to enter inside code .

Mutex only protect simultaneous access of resources if processes are belonging same priority.

consider below example for more details :

MUTEX BUG ON MBED PLATFORM


#include "mbed.h"  //MBED LIBRARY 

Mutex M_LOCK;  // Create MUTEX OBJECT  -class = MUTEX

//Create Two Thread 

Thread t2(osPriorityLow);  //Create Thread with high priority

Thread t3(osPriorityHigh); //Create Thread with low priority


//Here below section act as CS critical section

void common_function(const char *name, int state)  //TWO ARGUMENTS 1) WHO CALLED THIS FUNCTION 2)STATE OF CALLER
{
    printf("Thread arrive at door %s: %d\n\r", name, state);
    
    M_LOCK.lock();  //After arrive lock the code---------------------------LOCK THE BLOCK
    
    printf("This Thread lock the code %s: %d\n\r", name, state);
    wait(0.5); //sleep
    M_LOCK.unlock();  //After completing task unlock the code ------------- UNLOCK THE BLOCK
    
    printf("Thread cross & unlock %s: %d\n\r", name, state); //OUTSIDE CODE BLOCK 
}



//Function -We will connect more than one thread with this function
//So because of context switching this Function become shareable between multiple process.
void test_thread(void const *args)
{
    while (true) {
        common_function((const char *)args, 0);
        ThisThread::sleep_for(500);
        common_function((const char *)args, 1);
        ThisThread::sleep_for(500);
    }
}

int main()
{
    t2.start(callback(test_thread, (void *)"Th 2"));
    t3.start(callback(test_thread, (void *)"Th 3"));

    test_thread((void *)"Th 1");  // DIRECT CALL via main thread
}

and Output is something like shown in below imagehttps://os.mbed.com/media/uploads/radhey04ec/mutex_bug.jpg

As we can see here two process inside Critical section block , even mutex lock is there.

No, Its not true

Mutex have no any relation with Thread priority ...........Yes!!!!

https://os.mbed.com/media/uploads/radhey04ec/depositphotos_9199988-stock-photo-oops-icon_jIh7xAs.jpg

Here you are misguided by print statement.

PRINTF misleading you....

After unlock I have used print statement. print statement require more clock cycle compare to normal instruction. After unlock flag of Critical section , Scheduler quickly schedule waiting thread to use CS. And that's why printf after unlock() statement create wrong interpretation of MUTEX

Here is updated code :

#include "mbed.h"  //MBED LIBRARY 

Mutex M_LOCK;  // Create MUTEX OBJECT  -class = MUTEX

//Create Two Thread 

Thread t2;  

Thread t3; 


//Here below section act as CS critical section

void common_function(const char *name, int state)  //TWO ARGUMENTS 1) WHO CALLED THIS FUNCTION 2)STATE OF CALLER
{
    printf("Thread arrive at door %s: %d\n\r", name, state);
    
    M_LOCK.lock();  //After arrive lock the code---------------------------LOCK THE BLOCK
    
    printf("This Thread lock the code %s: %d\n\r", name, state);
    wait(0.5); //sleep
    printf("Thread cross & unlock %s: %d\n\r", name, state); //OUTSIDE CODE BLOCK ---------   
    M_LOCK.unlock();  //After completing task unlock the code ------------- UNLOCK THE BLOCK
    
//DO NOT WRITE any print statement after  unlock() it create missunderstanding ....
/* print statement require more clk cycle,after  unlock the MUTEX Flag - schedular quickly schedule next thread before print the statement.*/
}



//Function -- We will connect more than one thread with this function
//So because of context switching this Function become sharable between multiple process.
void test_thread(void const *args)
{
    while (true) {
        common_function((const char *)args, 0);
        ThisThread::sleep_for(500);
        common_function((const char *)args, 1);
        ThisThread::sleep_for(500);
    }
}

int main()
{
    t2.start(callback(test_thread, (void *)"Th 2"));
    t3.start(callback(test_thread, (void *)"Th 3"));

    test_thread((void *)"Th 1");  // DIRECT CALL via main thread
}



Please log in to post comments.