gnuk/ChibiOS_2.0.8/docs/html/article_mutual_exclusion.html
2010-11-30 13:54:43 +09:00

175 lines
12 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>ChibiOS/RT: Mutual Exclusion guide</title>
<link href="custom.css" rel="stylesheet" type="text/css">
<link href="tabs.css" rel="stylesheet" type="text/css">
</head><body>
<table style="text-align: center; width: 100%;" border="0"
cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="width: 80px;"><img alt="ChibiOS/RT Logo" src="logo_small.png"></td>
<td><big><big>ChibiOS/RT</big></big><br><br>Architecture - Reference Manual - Guides</td>
<td style="width: 80px;"></td>
</tr>
</tbody>
</table>
<hr size="1">
<!-- Generated by Doxygen 1.7.1 -->
<div class="navigation" id="top">
<div class="tabs">
<ul class="tablist">
<li><a href="main.html"><span>Main&nbsp;Page</span></a></li>
<li><a href="modules.html"><span>Modules</span></a></li>
<li><a href="annotated.html"><span>Data&nbsp;Structures</span></a></li>
<li><a href="files.html"><span>Files</span></a></li>
</ul>
</div>
<div class="navpath">
<ul>
<li><a class="el" href="main.html">ChibiOS/RT</a> </li>
<li><a class="el" href="articles.html">Articles and Code Samples</a> </li>
<li><a class="el" href="page_kb.html">Knowledge Base</a> </li>
</ul>
</div>
</div>
<div class="header">
<div class="headertitle">
<h1>Mutual Exclusion guide </h1> </div>
</div>
<div class="contents">
<p>The most common problem when writing multithreaded code is the synchronization on the shared resources/services.<br/>
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.</p>
<h2>Basics</h2>
<p>Some of the concepts mentioned in this article can be found in the following Wikipedia articles:</p>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Mutual_exclusion" target="_blank">Mutual Exclusion</a></li>
<li><a href="http://en.wikipedia.org/wiki/Priority_inversion" target="_blank">Priority Inversion</a></li>
<li><a href="http://en.wikipedia.org/wiki/Priority_inheritance" target="_blank">Priority Inheritance</a></li>
<li><a href="http://en.wikipedia.org/wiki/Priority_ceiling" target="_blank">Priority Ceiling</a></li>
</ul>
<h2>Mutual exclusion by System Locks</h2>
<p>This is the lowest level mechanism, the system is locked by invoking the <code><a class="el" href="group__system.html#ga9f6573c0763d1e4e97c63c62edad6e42" title="Enters the kernel lock mode.">chSysLock()</a></code> API and then unlocked by invoking <code><a class="el" href="group__system.html#ga5a257fa58a09815eb64a45e2dfbdc22e" title="Leaves the kernel lock mode.">chSysUnlock()</a></code>.<br/>
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.</p>
<h3>Advantages</h3>
<ul>
<li>It is the lightest as execution time, often a lock or unlock becomes just a single inlined assembler instruction.</li>
<li>It ensures mutual exclusion among threads but also interrupt handling code.</li>
<li>The implementation would ensure mutual exclusion even on multicore architectures where multiple hardware threads are present.</li>
</ul>
<h3>Disadvantages</h3>
<ul>
<li>Disabling interrupts for a long period of time can deteriorate the overall system response time and/or introduce jitter.</li>
</ul>
<h3>When use Locks</h3>
<ul>
<li>When mutual exclusion with interrupt handlers is required.</li>
<li>When the operation within the lock zone is very simple and has finite time.</li>
</ul>
<h3>Example</h3>
<div class="fragment"><pre class="fragment"> ...
<a class="code" href="group__system.html#ga9f6573c0763d1e4e97c63c62edad6e42" title="Enters the kernel lock mode.">chSysLock</a>();
<span class="comment">/* Protected code */</span>
<a class="code" href="group__system.html#ga5a257fa58a09815eb64a45e2dfbdc22e" title="Leaves the kernel lock mode.">chSysUnlock</a>();
...
</pre></div><h2>Mutual exclusion by Semaphores</h2>
<p>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.<br/>
The semaphores can, however, be used as simple mutexes by initializing the semaphore counter to one.</p>
<h3>Advantages</h3>
<ul>
<li>The semaphores code is "already there" if you use the I/O queues or mailboxes and you don't want to enable the mutexes too in order to save space.</li>
<li>Semaphores are lighter than mutexes because their queues are FIFO ordered and do not have any overhead caused by the priority inheritance algorithm.</li>
<li>A semaphore takes less RAM than a mutex (12 vs 16 bytes on 32 bit architectures).</li>
</ul>
<h3>Disadvantages</h3>
<ul>
<li><a class="el" href="struct_semaphore.html" title="Semaphore structure.">Semaphore</a> 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.</li>
<li>Semaphores do not implement the Priority Inheritance algorithm.</li>
</ul>
<h3>When use Semaphores</h3>
<ul>
<li>When you don't need queuing by priority nor the Priority Inheritance algorithm.</li>
<li>When RAM/ROM space is scarce.</li>
</ul>
<h3>Example</h3>
<div class="fragment"><pre class="fragment"> <span class="keyword">static</span> <a class="code" href="struct_semaphore.html" title="Semaphore structure.">Semaphore</a> sem; <span class="comment">/* Semaphore declaration */</span>
...
<a class="code" href="group__semaphores.html#gafe8fc6155a871074e8017efd908b2c58" title="Initializes a semaphore with the specified counter value.">chSemInit</a>(&amp;sem, 1); <span class="comment">/* Semaphore initialization before use */</span>
...
<a class="code" href="group__semaphores.html#gabc8f7e509870e9b0527a6a68fad71425" title="Performs a wait operation on a semaphore.">chSemWait</a>(&amp;sem);
<span class="comment">/* Protected code */</span>
<a class="code" href="group__semaphores.html#ga7ec0cbda23e49e2370e0b91f20baf05e" title="Performs a signal operation on a semaphore.">chSemSignal</a>(&amp;sem);
...
</pre></div><h2>Mutual exclusion by Mutexes</h2>
<p>The mutexes are the mechanism intended as the most general solution for Mutual Exclusion.</p>
<h3>Advantages</h3>
<ul>
<li>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 another tool for the system designer).</li>
</ul>
<h3>Disadvantages</h3>
<ul>
<li>Heaviest among all the possible choices. The Priority Inheritance method is efficiently implemented but nothing is more efficient than no code at all.</li>
</ul>
<h3>When use Mutexes</h3>
<ul>
<li>When you are designing a very complex system with hard realtime requirements.</li>
</ul>
<h3>Example</h3>
<div class="fragment"><pre class="fragment"> <span class="keyword">static</span> <a class="code" href="struct_mutex.html" title="Mutex structure.">Mutex</a> mtx; <span class="comment">/* Mutex declaration */</span>
...
<a class="code" href="group__mutexes.html#gac55fe4d05aa6bbeb31594193d2e4d2b6" title="Initializes s Mutex structure.">chMtxInit</a>(&amp;mtx); <span class="comment">/* Mutex initialization before use */</span>
...
<a class="code" href="group__mutexes.html#gafa06b82e3496c44eb7bf31d9f1b655ba" title="Locks the specified mutex.">chMtxLock</a>(&amp;mtx);
<span class="comment">/* Protected code */</span>
<a class="code" href="group__mutexes.html#gae9ae07165126c9f6c0ce0b17bdb53669" title="Unlocks the next owned mutex in reverse lock order.">chMtxUnlock</a>();
...
</pre></div><h2>Mutual exclusion by priority boost</h2>
<p>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.</p>
<h3>Advantages</h3>
<ul>
<li>Almost free as code size, you need no semaphores nor mutexes.</li>
<li>No RAM overhead.</li>
<li>Fast execution, priority change is a quick operation under ChibiOS/RT.</li>
<li>The Priority Ceiling protocol can help mitigate potential Priority Inversion problems.</li>
</ul>
<h3>Disadvantages</h3>
<ul>
<li>Makes the design more complicated because priorities must be assigned to not just threads but also assigned to the resources to be protected.</li>
<li>Locking a resource affects all the threads with lower priority even if not interested to the resource.</li>
<li>All the threads that can access the resource must have lower priority than the resource itself.</li>
<li>The mechanism is not easy to understand in the code unless it is clearly documented.</li>
<li>This method does not work in on multicore architectures where multiple hardware threads are present.</li>
<li>Only useful in very simple applications.</li>
</ul>
<h3>Example</h3>
<div class="fragment"><pre class="fragment"> <span class="comment">/* Priority assigned to the resource, threads must have lower</span>
<span class="comment"> priority than this.*/</span>
<span class="preprocessor"> #define AAA_RESOURCE_PRIORITY NORMALPRIO+10</span>
<span class="preprocessor"></span> ...
<span class="comment">/* Locks the resources AAA.*/</span>
<a class="code" href="group__types.html#ga5f2488ba73e5969cbc0f7033735374ee" title="Priority, use the fastest unsigned type.">tprio_t</a> aaa_old_prio = <a class="code" href="group__threads.html#ga5a5d9388c64e4c1a3aec129d2831eefe" title="Changes the running thread priority level then reschedules if necessary.">chThdSetPriority</a>(AAA_RESOURCE_PRIORITY);
<span class="comment">/* Accessing resource AAA */</span>
<a class="code" href="group__threads.html#ga5a5d9388c64e4c1a3aec129d2831eefe" title="Changes the running thread priority level then reschedules if necessary.">chThdSetPriority</a>(aaa_old_prio); <span class="comment">/* Unlocks AAA.*/</span>
...
</pre></div><h2>Mutual exclusion by message passing</h2>
<p>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.<br/>
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.</p>
<h3>Advantages</h3>
<ul>
<li>It is possible to encapsulate very complex logic without worry about about concurrent accesses.</li>
<li>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.</li>
<li>Clean system architecture.</li>
<li>This method also implements a form of Priority Ceiling. The ceiling is the priority of the server thread itself.</li>
</ul>
<h3>Disadvantages</h3>
<ul>
<li>More complex implementation, a protocol must be created between clients and server.</li>
<li>Two context switches are required for each request to the server (but ChibiOSRT is very efficient at that).</li>
<li>Requires a dedicated thread as server.</li>
</ul>
</div>
<hr size="1"><address style="text-align: right;"><small>
Generated on Sun Nov 28 2010 14:09:55 for ChibiOS/RT by&nbsp;<a href="http://www.doxygen.org/index.html"><img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.7.1</small></address>
</body>
</html>