/*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/**
* @page article_mutual_exclusion Mutual Exclusion guide
* The most common problem when writing multithreaded code is the
* synchronization on the shared resources/services.
* ChibiOS/RT offers a rich variety of mechanisms that apparently solve the
* same problem. I wrote apparently because each mechanism has its pro and
* cons.
* This article will introduce the various mechanisms and the explain the
* right scenarios for each one.
*
*
Basics
* Some of the concepts mentioned in this article can be found in the
* following Wikipedia articles:
* -
* Mutual Exclusion
* -
* Priority Inversion
* - Priority Inheritance
* -
* Priority Ceiling
* .
* Mutual exclusion by System Locks
* This is the lowest level mechanism, the system is locked by invoking the
* @p chSysLock() API and then unlocked by invoking @p chSysUnlock().
* The implementation is architecture dependent but it is guaranteed to, at
* least, disable the interrupt sources with hardware priority below or equal
* the kernel level.
*
* Advantages
* - It is the lightest as execution time, often a lock or unlock becomes just a
* single inlined assembler instruction.
* - It ensures mutual exclusion among threads but also interrupt handling code.
* - The implementation would ensure mutual exclusion even on multicore
* architectures where multiple hardware threads are present.
* .
* Disadvantages
* - Disabling interrupts for a long period of time can deteriorate the overall
* system response time and/or introduce jitter.
* .
* When use Locks
* - When mutual exclusion with interrupt handlers is required.
* - When the operation within the lock zone is very simple and has finite
* time.
* .
* Example
* @code
* ...
* chSysLock();
* /* Protected code */
* chSysUnlock();
* ...
* @endcode
*
* Mutual exclusion by Semaphores
* In ChibiOS/RT the counting semaphores are mainly meant as a
* synchronization mechanism between interrupt handlers and high level code
* running at thread level. Usually a thread waits on a semaphore that is
* signaled asynchronously by an interrupt handler.
* The semaphores can, however, be used as simple mutexes by initializing
* counter to one.
*
* Advantages
* - The semaphores code is "already there" if you use the I/O queues and
* you don't want to enable the mutexes too because space constraints.
* - Semaphores are lighter than mutexes because their queues are FIFO
* ordered and do not have any overhead caused by the priority inheritance
* algorithm.
* - A semaphore takes less RAM than a mutex (12 vs 16 bytes on 32 bit
* architectures).
* .
* Disadvantages
* - Semaphore queues are FIFO ordered by default, an option exist to make
* them priority ordered but this can impact I/O performance because
* semaphores are used in I/O queues.
* - Semaphores do not implement the Priority Inheritance algorithm.
* .
* When use Semaphores
* - When you don't need queuing by priority nor the Priority Inheritance
* algorithm.
* - When RAM/ROM space is scarce.
* .
* Example
* @code
* static Semaphore sem; /* Semaphore declaration */
* ...
* chSemInit(&sem, 1); /* Semaphore initialization before use */
* ...
* chSemWait(&sem);
* /* Protected code */
* chSemSignal(&sem);
* ...
* @endcode
*
* Mutual exclusion by Mutexes
* The mutexes, also known as binary semaphores (we choose to not use this
* terminology to avoid confusion with counting semaphores), are the mechanism
* intended as general solution for Mutual Exclusion.
*
* Advantages
* - Mutexes implement the Priority Inheritance algorithm that is an important
* tool in reducing jitter and improve overall system response time (it is
* not a magic solution, just a tool for the system designer).
* .
* Disadvantages
* - Heaviest among all the possible choices. The Priority Inheritance method
* is efficiently implemented but nothing is more efficient than no code at
* all.
* .
* When use Mutexes
* - When you are designing a very complex system with hard realtime
* requirements.
* .
* Example
* @code
* static Mutex mtx; /* Mutex declaration */
* ...
* chMtxInit(&mtx); /* Mutex initialization before use */
* ...
* chMtxLock(&mtx);
* /* Protected code */
* chMtxUnlock();
* ...
* @endcode
*
* Mutual exclusion by priority boost
* Another way to implement mutual exclusion is to boost the thread priority
* to a level higher than all of the threads competing for a certain resource.
* This solution effectively implements an Immediate Priority Ceiling
* algorithm.
*
* Advantages
* - Almost free as code size, you need no semaphores nor mutexes.
* - No RAM overhead.
* - Fast execution, priority change is a quick operation under ChibiOS/RT.
* - The Priority Ceiling protocol can help mitigate potential Priority
* Inversion problems.
* .
* Disadvantages
* - Makes the design more complicated because priorities must be assigned to
* not just threads but also assigned to the resources to be protected.
* - Locking a resource affects all the threads with lower priority even if
* not interested to the resource.
* - All the threads that can access the resource must have lower priority
* than the resource itself.
* - The mechanism is not easy to understand in the code unless it is clearly
* documented.
* - This method does not work in on multicore architectures where multiple
* hardware threads are present.
* - Only useful in very simple applications.
* .
* Example
* @code
* /* Priority assigned to the resource, threads must have lower
* priority than this.*/
* #define AAA_RESOURCE_PRIORITY NORMALPRIO+10
* ...
* /* Locks the resources AAA.*/
* tprio_t aaa_old_prio = chThdSetPriority(AAA_RESOURCE_PRIORITY);
* /* Accessing resource AAA */
* chThdSetPriority(aaa_old_prio); /* Unlocks AAA.*/
* ...
* @endcode
*
* Mutual exclusion by message passing
* Another method is to make a single dedicated thread execute the critical
* code and make it work as a messages server. The other threads can request
* the service to the server by sending a properly formatted message and
* then wait for the answer with the result.
* This method is very useful when integrating into the system components not
* designed to be reentrant or to be executed in a multithreaded environment,
* as example a 3rd part file system or a networking protocol stack.
*
* Advantages
* - It is possible to encapsulate very complex logic without worry about
* about concurrent accesses.
* - If the encapsulate code uses a large stack area only the server thread
* have to allocate enough RAM, the client threads save RAM by just
* requesting the service to the server.
* - Clean system architecture.
* - This method also implements a form of Priority Ceiling. The ceiling is
* the priority of the server thread itself.
* .
* Disadvantages
* - More complex implementation, a protocol must be created between clients
* and server.
* - Two context switches are required for each request to the server (but
* ChibiOSRT is very efficient at that).
* - Requires a dedicated thread as server.
* .
*/