📄 kernel-mutexes.html
字号:
<!-- Copyright (C) 2003 Red Hat, Inc. -->
<!-- This material may be distributed only subject to the terms -->
<!-- and conditions set forth in the Open Publication License, v1.0 -->
<!-- or later (the latest version is presently available at -->
<!-- http://www.opencontent.org/openpub/). -->
<!-- Distribution of the work or derivative of the work in any -->
<!-- standard (paper) book form is prohibited unless prior -->
<!-- permission is obtained from the copyright holder. -->
<HTML
><HEAD
><TITLE
>Mutexes</TITLE
><meta name="MSSmartTagsPreventParsing" content="TRUE">
<META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
"><LINK
REL="HOME"
TITLE="eCos Reference Manual"
HREF="ecos-ref.html"><LINK
REL="UP"
TITLE="The eCos Kernel"
HREF="kernel.html"><LINK
REL="PREVIOUS"
TITLE="Alarms"
HREF="kernel-alarms.html"><LINK
REL="NEXT"
TITLE="Condition Variables"
HREF="kernel-condition-variables.html"></HEAD
><BODY
CLASS="REFENTRY"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>eCos Reference Manual</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="kernel-alarms.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="kernel-condition-variables.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><H1
><A
NAME="KERNEL-MUTEXES">Mutexes</H1
><DIV
CLASS="REFNAMEDIV"
><A
NAME="AEN1098"
></A
><H2
>Name</H2
>cyg_mutex_init, cyg_mutex_destroy, cyg_mutex_lock, cyg_mutex_trylock, cyg_mutex_unlock, cyg_mutex_release, cyg_mutex_set_ceiling, cyg_mutex_set_protocol -- Synchronization primitive</DIV
><DIV
CLASS="REFSYNOPSISDIV"
><A
NAME="AEN1108"><H2
>Synopsis</H2
><DIV
CLASS="FUNCSYNOPSIS"
><A
NAME="AEN1109"><P
></P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="FUNCSYNOPSISINFO"
>#include <cyg/kernel/kapi.h>
</PRE
></TD
></TR
></TABLE
><P
><CODE
><CODE
CLASS="FUNCDEF"
>void cyg_mutex_init</CODE
>(cyg_mutex_t* mutex);</CODE
></P
><P
><CODE
><CODE
CLASS="FUNCDEF"
>void cyg_mutex_destroy</CODE
>(cyg_mutex_t* mutex);</CODE
></P
><P
><CODE
><CODE
CLASS="FUNCDEF"
>cyg_bool_t cyg_mutex_lock</CODE
>(cyg_mutex_t* mutex);</CODE
></P
><P
><CODE
><CODE
CLASS="FUNCDEF"
>cyg_bool_t cyg_mutex_trylock</CODE
>(cyg_mutex_t* mutex);</CODE
></P
><P
><CODE
><CODE
CLASS="FUNCDEF"
>void cyg_mutex_unlock</CODE
>(cyg_mutex_t* mutex);</CODE
></P
><P
><CODE
><CODE
CLASS="FUNCDEF"
>void cyg_mutex_release</CODE
>(cyg_mutex_t* mutex);</CODE
></P
><P
><CODE
><CODE
CLASS="FUNCDEF"
>void cyg_mutex_set_ceiling</CODE
>(cyg_mutex_t* mutex, cyg_priority_t priority);</CODE
></P
><P
><CODE
><CODE
CLASS="FUNCDEF"
>void cyg_mutex_set_protocol</CODE
>(cyg_mutex_t* mutex, enum cyg_mutex_protocol protocol/);</CODE
></P
><P
></P
></DIV
></DIV
><DIV
CLASS="REFSECT1"
><A
NAME="KERNEL-MUTEXES-DESCRIPTION"
></A
><H2
>Description</H2
><P
>The purpose of mutexes is to let threads share resources safely. If
two or more threads attempt to manipulate a data structure with no
locking between them then the system may run for quite some time
without apparent problems, but sooner or later the data structure will
become inconsistent and the application will start behaving strangely
and is quite likely to crash. The same can apply even when
manipulating a single variable or some other resource. For example,
consider:
</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>static volatile int counter = 0;
void
process_event(void)
{
…
counter++;
}</PRE
></TD
></TR
></TABLE
><P
>Assume that after a certain period of time <TT
CLASS="VARNAME"
>counter</TT
>
has a value of 42, and two threads A and B running at the same
priority call <TT
CLASS="FUNCTION"
>process_event</TT
>. Typically thread A
will read the value of <TT
CLASS="VARNAME"
>counter</TT
> into a register,
increment this register to 43, and write this updated value back to
memory. Thread B will do the same, so usually
<TT
CLASS="VARNAME"
>counter</TT
> will end up with a value of 44. However if
thread A is timesliced after reading the old value 42 but before
writing back 43, thread B will still read back the old value and will
also write back 43. The net result is that the counter only gets
incremented once, not twice, which depending on the application may
prove disastrous.
</P
><P
>Sections of code like the above which involve manipulating shared data
are generally known as critical regions. Code should claim a lock
before entering a critical region and release the lock when leaving.
Mutexes provide an appropriate synchronization primitive for this.
</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>static volatile int counter = 0;
static cyg_mutex_t lock;
void
process_event(void)
{
…
cyg_mutex_lock(&lock);
counter++;
cyg_mutex_unlock(&lock);
}
</PRE
></TD
></TR
></TABLE
><P
>A mutex must be initialized before it can be used, by calling
<TT
CLASS="FUNCTION"
>cyg_mutex_init</TT
>. This takes a pointer to a
<SPAN
CLASS="STRUCTNAME"
>cyg_mutex_t</SPAN
> data structure which is typically
statically allocated, and may be part of a larger data structure. If a
mutex is no longer required and there are no threads waiting on it
then <TT
CLASS="FUNCTION"
>cyg_mutex_destroy</TT
> can be used.
</P
><P
>The main functions for using a mutex are
<TT
CLASS="FUNCTION"
>cyg_mutex_lock</TT
> and
<TT
CLASS="FUNCTION"
>cyg_mutex_unlock</TT
>. In normal operation
<TT
CLASS="FUNCTION"
>cyg_mutex_lock</TT
> will return success after claiming
the mutex lock, blocking if another thread currently owns the mutex.
However the lock operation may fail if other code calls
<TT
CLASS="FUNCTION"
>cyg_mutex_release</TT
> or
<TT
CLASS="FUNCTION"
>cyg_thread_release</TT
>, so if these functions may get
used then it is important to check the return value. The current owner
of a mutex should call <TT
CLASS="FUNCTION"
>cyg_mutex_unlock</TT
> when a
lock is no longer required. This operation must be performed by the
owner, not by another thread.
</P
><P
><TT
CLASS="FUNCTION"
>cyg_mutex_trylock</TT
> is a variant of
<TT
CLASS="FUNCTION"
>cyg_mutex_lock</TT
> that will always return
immediately, returning success or failure as appropriate. This
function is rarely useful. Typical code locks a mutex just before
entering a critical region, so if the lock cannot be claimed then
there may be nothing else for the current thread to do. Use of this
function may also cause a form of priority inversion if the owner
owner runs at a lower priority, because the priority inheritance code
will not be triggered. Instead the current thread continues running,
preventing the owner from getting any cpu time, completing the
critical region, and releasing the mutex.
</P
><P
><TT
CLASS="FUNCTION"
>cyg_mutex_release</TT
> can be used to wake up all
threads that are currently blocked inside a call to
<TT
CLASS="FUNCTION"
>cyg_mutex_lock</TT
> for a specific mutex. These lock
calls will return failure. The current mutex owner is not affected.
</P
></DIV
><DIV
CLASS="REFSECT1"
><A
NAME="KERNEL-MUTEXES-PRIORITY-INVERSION"
></A
><H2
>Priority Inversion</H2
><P
>The use of mutexes gives rise to a problem known as priority
inversion. In a typical scenario this requires three threads A, B, and
C, running at high, medium and low priority respectively. Thread A and
thread B are temporarily blocked waiting for some event, so thread C
gets a chance to run, needs to enter a critical region, and locks
a mutex. At this point threads A and B are woken up - the exact order
does not matter. Thread A needs to claim the same mutex but has to
wait until C has left the critical region and can release the mutex.
Meanwhile thread B works on something completely different and can
continue running without problems. Because thread C is running a lower
priority than B it will not get a chance to run until B blocks for
some reason, and hence thread A cannot run either. The overall effect
is that a high-priority thread A cannot proceed because of a lower
priority thread B, and priority inversion has occurred.
</P
><P
>In simple applications it may be possible to arrange the code such
that priority inversion cannot occur, for example by ensuring that a
given mutex is never shared by threads running at different priority
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -