Friday, December 16, 2011

Mutex vs Binary Semaphore

How a binary semaphore is different from a mutex in usage.Also state the limitations of a mutex and a binary semaphore

Why a mutex cant be relased from an ISR:
Remember that a Mutex must first be acquired/taken then released/given. In addition, the task that acquires the mutex owns it. This prevents another task from releasing a mutex it doesn't own.
With that being the case, it becomes clear that since an ISR cannot acquire a mutex (or any semaphore for that matter - it's a blocking operation), then it follows that it can't give the mutex.
It is quite possible for an ISR to do give a Binary or Counting semaphore to signal a task that something happens. But mutexes are always a take/give pair.
To clarify a point. In VxWorks, the ISR context is not the same as the context of a task!

The following scenario is invalid:
  Task A            ISR
  semTake(mutex)
   ....
                    semGive(mutex)
Task A owns the mutex. When the ISR runs, it executes in a totaly different context. Most current processors have a separate ISR stack. Since Task A owns the mutex, how could the ISR give it up? In fact, what guarantee do you have that the ISR will fire while A has the mutex.

Even assuming you "could" give a mutex in an ISR, how would you handle the following scenario:
 Task A                       Task B                 ISR
  semTake(mutex)
  ...
  <context switch happens>
                              <B runs>
                                                  semGive(mutex)
Task A gets switched out due to a call unrelated to the mutex, and Task B runs. The ISR now executes while B was running. Would it still be valid for the ISR to be given?
Regardless of all this, the simple fact is that a mutex is always used in a pair of Get/Set. I fail to see a use case where you would have an isolated semGive.


Useful Links:-
http://www.chibios.org/dokuwiki/doku.php?id=chibios:articles:semaphores_mutexes
http://www.smxrtos.com/articles/techppr/mutex.htm

1 comment:

  1. Consider the following code example, which uses a counting or binary semaphore:

    functionA()
    {
    SemWait(semA, INF);
    functionX();
    SemSignal(semA);
    }

    FunctionX()
    {
    SemWait(semA, INF);
    ...
    SemSignal(semA);
    }

    In this example, both functionA and functionX need access to a resource that is protected by semA. functionA, while accessing this resource, calls functionX. When this happens the current task (which is running functionA) is suspended indefinitely [1] on semA because functionX tests semA a second time. This happens because semA does not know that the current task already owns it.

    For this, a mutex has an advantage over a counting or binary semaphore. When owned, the mutex knows which task owns it. A second test by the same task will not fail and the task will not be suspended. Hence, the above code, which could easily occur when using a thread-safe library, will not cause the current task to freeze.

    Another kernel provides a resource semaphore, which is the same as a mutex, except that it gives an error if a task tests it a second time. This is intended to catch unmatched tests vs. signals. However, this is not the more likely problem - it is natural to put matched tests and signals into a routine. Non-matches can be found simply by searching for SemSignal and SemTest for the same semaphore - the two counts should be equal. The more difficult problem to detect is the one described above because the user of a library may not be aware that one function calls another and that both test the same mutex.

    Premature Release

    We are still not out of the woods with respect to the above example. It is not acceptable for semA to be released by the signal in functionX, because functionA, which called functionX, is still in its critical section. For every test, there must be a matching signal, before the mutex can become free. This is assured by having an internal nesting counter in the mutex. This counter is incremented by every test from the owner task and decremented by every signal from the owner task. Only tests and signals from the owner task can change the nesting counter. When it reaches zero, the mutex is freed.

    ReplyDelete