plan9port/man/man3/lock.html

223 lines
9.8 KiB
HTML
Raw Normal View History

2005-01-14 03:45:44 +00:00
<head>
<title>lock(3) - Plan 9 from User Space</title>
<meta content="text/html; charset=utf-8" http-equiv=Content-Type>
</head>
<body bgcolor=#ffffff>
<table border=0 cellpadding=0 cellspacing=0 width=100%>
<tr height=10><td>
<tr><td width=20><td>
<tr><td width=20><td><b>LOCK(3)</b><td align=right><b>LOCK(3)</b>
<tr><td width=20><td colspan=2>
<br>
<p><font size=+1><b>NAME </b></font><br>
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
lock, canlock, unlock, qlock, canqlock, qunlock, rlock, canrlock,
runlock, wlock, canwlock, wunlock, rsleep, rwakeup, rwakeupall
incref, decref &ndash; spin locks, queueing rendezvous locks, reader-writer
locks, rendezvous points, and reference counts<br>
</table>
<p><font size=+1><b>SYNOPSIS </b></font><br>
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
<tt><font size=+1>#include &lt;u.h&gt;<br>
#include &lt;libc.h&gt;<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
void lock(Lock *l)<br>
int &nbsp;&nbsp;&nbsp;canlock(Lock *l)<br>
void unlock(Lock *l)<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
void qlock(QLock *l)<br>
int &nbsp;&nbsp;&nbsp;canqlock(QLock *l)<br>
void qunlock(QLock *l)<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
void rlock(RWLock *l)<br>
int &nbsp;&nbsp;&nbsp;canrlock(RWLock *l)<br>
void runlock(RWLock *l)<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
void wlock(RWLock *l)<br>
int &nbsp;&nbsp;&nbsp;canwlock(RWLock *l)<br>
void wunlock(RWLock *l)<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
typedef struct Rendez {<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
QLock *l;<br>
</table>
</font></tt>
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
<i>...<br>
</i>
</table>
<tt><font size=+1>} Rendez;<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
void rsleep(Rendez *r)<br>
int &nbsp;&nbsp;&nbsp;rwakeup(Rendez *r)<br>
int &nbsp;&nbsp;&nbsp;rwakeupall(Rendez *r)<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
#include &lt;thread.h&gt;<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
typedef struct Ref {<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
long ref;<br>
</table>
} Ref;<br>
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
void incref(Ref*)<br>
long decref(Ref*)<br>
</font></tt>
</table>
<p><font size=+1><b>DESCRIPTION </b></font><br>
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
These routines are used to synchronize processes sharing memory.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
<tt><font size=+1>Locks</font></tt> are spin locks, <tt><font size=+1>QLocks</font></tt> and <tt><font size=+1>RWLocks</font></tt> are different types of
queueing locks, and <tt><font size=+1>Rendezes</font></tt> are rendezvous points.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
Locks and rendezvous points have trivial implementations in programs
not using the thread library (see <a href="../man3/thread.html"><i>thread</i>(3)</a>), since such programs
have no concurrency.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
Used carelessly, spin locks can be expensive and can easily generate
deadlocks. Their use is discouraged, especially in programs that
use the thread library because they prevent context switches between
threads.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
<i>Lock</i> blocks until the lock has been obtained. <i>Canlock</i> is non-blocking.
It tries to obtain a lock and returns a non-zero value if it was
successful, 0 otherwise. <i>Unlock</i> releases a lock.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
<tt><font size=+1>QLocks</font></tt> have the same interface but are not spin locks; instead
if the lock is taken <i>qlock</i> will suspend execution of the calling
thread until it is released.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
Although <tt><font size=+1>Locks</font></tt> are the more primitive lock, they have limitations;
for example, they cannot synchronize between tasks in the same
<i>proc</i>. Use <tt><font size=+1>QLocks</font></tt> instead.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
<tt><font size=+1>RWLocks</font></tt> manage access to a data structure that has distinct readers
and writers. <i>Rlock</i> grants read access; <i>runlock</i> releases it. <i>Wlock</i>
grants write access; <i>wunlock</i> releases it. <i>Canrlock</i> and <i>canwlock</i>
are the non-blocking versions. There may be any number of simultaneous
readers, but only one writer. Moreover, if
write access is granted no one may have read access until write
access is released.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
All types of lock should be initialized to all zeros before use;
this puts them in the unlocked state.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
<tt><font size=+1>Rendezes</font></tt> are rendezvous points. Each <tt><font size=+1>Rendez</font></tt> <i>r</i> is protected by
a <tt><font size=+1>QLock</font></tt> <i>r</i><tt><font size=+1>&#8722;&gt;</font></tt><i>l</i>, which must be held by the callers of <i>rsleep</i>, <i>rwakeup</i>,
and <i>rwakeupall</i>. <i>Rsleep</i> atomically releases <i>r</i><tt><font size=+1>&#8722;&gt;</font></tt><i>l</i> and suspends execution
of the calling task. After resuming execution, <i>rsleep</i> will reacquire
<i>r</i><tt><font size=+1>&#8722;&gt;</font></tt><i>l</i> before returning. If any processes
are sleeping on <i>r</i>, <i>rwakeup</i> wakes one of them. it returns 1 if
a process was awakened, 0 if not. <i>Rwakeupall</i> wakes all processes
sleeping on <i>r</i>, returning the number of processes awakened. <i>Rwakeup</i>
and <i>rwakeupall</i> do not release <i>r</i><tt><font size=+1>&#8722;&gt;</font></tt><i>l</i> and do not suspend execution
of the current task.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
Before use, <tt><font size=+1>Rendezes</font></tt> should be initialized to all zeros except
for <i>r</i><tt><font size=+1>&#8722;&gt;</font></tt><i>l</i> pointer, which should point at the <tt><font size=+1>QLock</font></tt> that will guard
<i>r</i>.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
A <tt><font size=+1>Ref</font></tt> contains a <tt><font size=+1>long</font></tt> that can be incremented and decremented
atomically: <i>Incref</i> increments the <i>Ref</i> in one atomic operation.
<i>Decref</i> atomically decrements the <tt><font size=+1>Ref</font></tt> and returns zero if the resulting
value is zero, non-zero otherwise.<br>
</table>
<p><font size=+1><b>SOURCE </b></font><br>
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
<tt><font size=+1>/usr/local/plan9/src/lib9/qlock.c<br>
/usr/local/plan9/src/libthread<br>
</font></tt>
</table>
<p><font size=+1><b>BUGS </b></font><br>
<table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>
<tt><font size=+1>Locks</font></tt> are not always spin locks. Instead they are usually implemented
using the <i>pthreads</i> library&#8217;s <tt><font size=+1>pthread_mutex_t</font></tt>, whose implementation
method is not defined.
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
On <i>pthreads</i>-based systems, the implementation of <tt><font size=+1>Lock</font></tt> never calls
<i>pthread_mutex_destroy</i> to free the <tt><font size=+1>pthread_mutex_t</font></tt>&#8217;s. This leads
to resource leaks on FreeBSD 5 (though not on Linux 2.6, where
<i>pthread_mutex_destroy</i> is a no-op).
<table border=0 cellpadding=0 cellspacing=0><tr height=5><td></table>
On systems that do not have a usable <i>pthreads</i> implementation,
the <tt><font size=+1>Lock</font></tt> implementation provided by <i>libthread</i> is still not exactly
a spin lock. After each unsuccessful attempt, <i>lock</i> calls <tt><font size=+1>sleep(0)</font></tt>
to yield the CPU; this handles the common case where some other
process holds the lock. After a thousand
unsuccessful attempts, <i>lock</i> sleeps for 100ms between attempts.
Another another thousand unsuccessful attempts, <i>lock</i> sleeps for
a full second between attempts. <tt><font size=+1>Locks</font></tt> are not intended to be held
for long periods of time. The 100ms and full second sleeps are
only heuristics to avoid tying up the CPU when a
process deadlocks. As discussed above, if a lock is to be held
for much more than a few instructions, the queueing lock types
should be almost always be used.<br>
</table>
<td width=20>
<tr height=20><td>
</table>
<!-- TRAILER -->
<table border=0 cellpadding=0 cellspacing=0 width=100%>
<tr height=15><td width=10><td><td width=10>
<tr><td><td>
<center>
<a href="../../"><img src="../../dist/spaceglenda100.png" alt="Space Glenda" border=1></a>
</center>
</table>
<!-- TRAILER -->
</body></html>