Standard C Library Functions mutexinit(3C)
NAME
mutexinit, mutexlock, mutextrylock, mutexunlock,
mutexconsistent, mutexdestroy - mutual exclusion locks
SYNOPSIS
cc -mt [ flag... ] file... [ library... ]
#include
#include
int mutexinit(mutext *mp, int type, void * arg);
int mutexlock(mutext *mp);
int mutextrylock(mutext *mp);
int mutexunlock(mutext *mp);
int mutexconsistent(mutext *mp);
int mutexdestroy(mutext *mp);
DESCRIPTION
Mutual exclusion locks (mutexes) prevent multiple threads
from simultaneously executing critical sections of code that
access shared data (that is, mutexes are used to serialize
the execution of threads). All mutexes must be global. A
successful call for a mutex lock by way of mutexlock()
will cause another thread that is also trying to lock the
same mutex to block until the owner thread unlocks it by way
of mutexunlock(). Threads within the same process or
within other processes can share mutexes.
Mutexes can synchronize threads within the same process or
in other processes. Mutexes can be used to synchronize
threads between processes if the mutexes are allocated in
writable memory and shared among the cooperating processes
(see mmap(2)), and have been initialized for this task.
Initialize
Mutexes are either intra-process or inter-process, depending
upon the argument passed implicitly or explicitly to the
initialization of that mutex. A statically allocated mutex
does not need to be explicitly initialized; by default, a
statically allocated mutex is initialized with all zeros
and its scope is set to be within the calling process.
SunOS 5.11 Last change: 5 Jun 2007 1
Standard C Library Functions mutexinit(3C)
For inter-process synchronization, a mutex needs to be allo-
cated in memory shared between these processes. Since the
memory for such a mutex must be allocated dynamically, the
mutex needs to be explicitly initialized using mutexinit().
The mutexinit() function initializes the mutex referenced
by mp with the type specified by type. Upon successful ini-
tialization the state of the mutex becomes initialized and
unlocked. Only the attribute type LOCKPRIOPROTECT uses
arg. The type argument must be one of the following:
USYNCTHREAD
The mutex can synchronize threads only in this process.
USYNCPROCES
The mutex can synchronize threads in this process and
other processes. The object initialized with this attri-
bute must be allocated in memory shared between
processes, either in System V shared memory (see
shmop(2)) or in memory mapped to a file (see mmap(2)).
If the object is not allocated in such shared memory, it
will not be shared between processes.
The type argument can be augmented by the bitwise-
inclusive-OR of zero or more of the following flags:
LOCKROBUST
The mutex can synchronize threads robustly. At the time
of thread or process death, either by calling threxit()
or exit() or due to process abnormal termination, the
lock is unlocked if is held by the thread or process.
The next owner of the mutex will acquire it with an
error return of EOWNERDEAD. The application must always
check the return value from mutexlock() for a mutex of
this type. The new owner of this mutex should then
attempt to make the state protected by the mutex con-
sistent, since this state could have been left incon-
sistent when the last owner died. If the new owner is
able to make the state consistent, it should call
mutexconsistent() to restore the state of the mutex and
then unlock the mutex. All subsequent calls to
mutexlock()will then behave normally. Only the new
owner can make the mutex consistent. If for any reason
the new owner is not able to make the state consistent,
it should not call mutexconsistent() but should simply
SunOS 5.11 Last change: 5 Jun 2007 2
Standard C Library Functions mutexinit(3C)
unlock the mutex. All waiting processes will be awakened
and all subsequent calls to mutexlock() will fail in
acquiring the mutex with an error value of ENOTRECOVER-
ABLE. If the thread or process that acquired the lock
with EOWNERDEAD terminates without unlocking the mutex,
the next owner will acquire the lock with an error value
of EOWNERDEAD.
The memory for the object to be initialized with this
attribute must be zeroed before initialization. Any
thread or process interested in the robust lock can call
mutexinit() to potentially initialize it, provided that
all such callers of mutexinit() specify the same set of
attribute flags. In this situation, if mutexinit() is
called on a previously initialized robust mutex,
mutexinit() will not reinitialize the mutex and will
return the error value EBUSY.
LOCKRECURSIVE
A thread attempting to relock this mutex without first
unlocking it will succeed in locking the mutex. The
mutex must be unlocked as many times as it is locked.
LOCKERORCHECK
Unless LOCKRECURSIVE is also set, a thread attempting
to relock this mutex without first unlocking it will
return with an error rather than deadlocking itself. A
thread attempting to unlock this mutex without first
owning it will return with an error.
LOCKPRIOINHERIT
When a thread is blocking higher priority threads
because of owning one or more mutexes with the
LOCKPRIOINHERIT attribute, it executes at the higher
of its priority or the priority of the highest priority
thread waiting on any of the mutexes owned by this
thread and initialized with this attribute.
LOCKPRIOPROTECT
When a thread owns one or more mutexes initialized with
the LOCKPRIOPROTECT attribute, it executes at the
higher of its priority or the highest of the priority
ceilings of all the mutexes owned by this thread and
initialized with this attribute, regardless of whether
SunOS 5.11 Last change: 5 Jun 2007 3
Standard C Library Functions mutexinit(3C)
other threads are blocked on any of these mutexes. When
this attribute is specified, arg must point to an int
containing the priority ceiling.
See pthreadmutexattrgetrobust(3C) for more information
about robust mutexes. The LOCKROBUST attribute is the same
as the POSIX PTHREADMUTEXROBUST attribute.
See pthreadmutexattrsettype(3C) for more information on
recursive and error checking mutex types. The combination
(LOCKRECURSIVE LOCKERORCHECK) is the same as the POSIX
PTHREADMUTEXRECURSIVE type. By itself, LOCKERORCHECK is
the same as the POSIX PTHREADMUTEXERORCHECK type.
The LOCKPRIOINHERIT attribute is the same as the POSIX
PTHREADPRIOINHERIT attribute. The LOCKPRIOPROTECT attri-
bute is the same as the POSIX PTHREADPRIOPROTECT attri-
bute. See pthreadmutexattrgetprotocol(3C),
pthreadmutexattrgetprioceiling(3C), and
pthreadmutexgetprioceiling(3C) for a full discussion. The
LOCKPRIOINHERIT and LOCKPRIOPROTECT attributes are mutu-
ally exclusive. Specifying both of these attributes causes
mutexinit() to fail with EINVAL.
Initializing mutexes can also be accomplished by allocating
in zeroed memory (default), in which case a type of
USYNCTHREAD is assumed. In general, the following rules
apply to mutex initialization:
o The same mutex must not be simultaneously initial-
ized by multiple threads.
o A mutex lock must not be reinitialized while in use
by other threads.
These rules do not apply to LOCKROBUST mutexes. See the
description for LOCKROBUSTabove. If default mutex attri-
butes are used, the macro DEFAULTMUTEX can be used to ini-
tialize mutexes that are statically allocated.
Default mutex initialization (intra-process):
mutext mp;
mutexinit(&mp, USYNCTHREAD, NUL);
SunOS 5.11 Last change: 5 Jun 2007 4
Standard C Library Functions mutexinit(3C)
or
mutext mp = DEFAULTMUTEX;
Customized mutex initialization (inter-process):
mutexinit(&mp, USYNCPROCES, NUL);
Customized mutex initialization (inter-process robust):
mutexinit(&mp, USYNCPROCES LOCKROBUST, NUL);
Statically allocated mutexes can also be initialized with
macros specifying LOCKRECURSIVE and/or LOCKERORCHECK:
mutext mp = RECURSIVEMUTEX;
Same as (USYNCTHREAD LOCKRECURSIVE)
mutext mp = ERORCHECKMUTEX;
Same as (USYNCTHREAD LOCKERORCHECK)
mutext mp = RECURSIVERORCHECKMUTEX;
Same as (USYNCTHREAD LOCKRECURSIVE
LOCKERORCHECK)
Lock and Unlock
A critical section of code is enclosed by a the call to
lock the mutex and the call to unlock the mutex to protect
it from simultaneous access by multiple threads. Only one
thread at a time may possess mutually exclusive access to
the critical section of code that is enclosed by the mutex-
locking call and the mutex-unlocking call, whether the
mutex's scope is intra-process or inter-process. A thread
calling to lock the mutex either gets exclusive access to
the code starting from the successful locking until its call
to unlock the mutex, or it waits until the mutex is unlocked
by the thread that locked it.
SunOS 5.11 Last change: 5 Jun 2007 5
Standard C Library Functions mutexinit(3C)
Mutexes have ownership, unlike semaphores. Although any
thread, within the scope of a mutex, can get an unlocked
mutex and lock access to the same critical section of code,
only the thread that locked a mutex should unlock it.
If a thread waiting for a mutex receives a signal, upon
return from the signal handler, the thread resumes waiting
for the mutex as if there was no interrupt. A mutex protects
code, not data; therefore, strongly bind a mutex with the
data by putting both within the same structure, or at least
within the same procedure.
A call to mutexlock() locks the mutex object referenced by
mp. If the mutex is already locked, the calling thread
blocks until the mutex is freed; this will return with the
mutex object referenced by mp in the locked state with the
calling thread as its owner. If the current owner of a mutex
tries to relock the mutex, it will result in deadlock.
The mutextrylock() function is the same as mutexlock(),
respectively, except that if the mutex object referenced by
mp is locked (by any thread, including the current thread),
the call returns immediately with an error.
The mutexunlock() function are called by the owner of the
mutex object referenced by mp to release it. The mutex must
be locked and the calling thread must be the one that last
locked the mutex (the owner). If there are threads blocked
on the mutex object referenced by mp when mutexunlock() is
called, the mp is freed, and the scheduling policy will
determine which thread gets the mutex. If the calling thread
is not the owner of the lock, no error status is returned,
and the behavior of the program is undefined.
Destroy
The mutexdestroy() function destroys the mutex object
referenced by mp. The mutex object becomes uninitialized.
The space used by the destroyed mutex variable is not freed.
It needs to be explicitly reclaimed.
RETURN VALUES
If successful, these functions return 0. Otherwise, an error
number is returned.
ERORS
The mutexinit() function will fail if:
SunOS 5.11 Last change: 5 Jun 2007 6
Standard C Library Functions mutexinit(3C)
EINVAL The value specified by type is invalid, or the
LOCKPRIOINHERIT and LOCKPRIOPROTECT attributes
are both specified.
The mutexinit() function will fail for LOCKROBUST type
mutex if:
EBUSY The mutex pointed to by mp was previously ini-
tialized and has not yet been destroyed.
EINVAL The mutex pointed to by mp was previously initial-
ized with a different set of attribute flags.
The mutextrylock() function will fail if:
EBUSY The mutex pointed to by mp is already locked.
The mutexlock() and mutextrylock() functions will fail for
a LOCKRECURSIVE mutex if:
EAGAIN The mutex could not be acquired because the max-
imum number of recursive locks for the mutex has
been reached.
The mutexlock() function will fail for a LOCKERORCHECK
and non-LOCKRECURSIVE mutex if:
EDEADLK The caller already owns the mutex.
The mutexlock() function may fail for a non-LOCKERORCHECK
and non-LOCKRECURSIVE mutex if:
EDEADLK The caller already owns the mutex.
The mutexunlock() function will fail for a LOCKERORCHECK
mutex if:
EPERM The caller does not own the mutex.
SunOS 5.11 Last change: 5 Jun 2007 7
Standard C Library Functions mutexinit(3C)
The mutexlock() or mutextrylock() functions will fail for
LOCKROBUST type mutex if:
EOWNERDEAD The last owner of this mutex died while
holding the mutex. This mutex is now
owned by the caller. The caller must now
attempt to make the state protected by
the mutex consistent. If it is able to
clean up the state, then it should
restore the state of the mutex by calling
mutexconsistent() and unlock the mutex.
Subsequent calls to mutexlock() will
behave normally, as before. If the caller
is not able to clean up the state,
mutexconsistent() should not be called
but the mutex should be unlocked. Subse-
quent calls to mutexlock() will fail to
acquire the mutex, returning with the
error value ENOTRECOVERABLE. If the owner
who acquired the lock with EOWNERDEAD
dies, the next owner will acquire the
lock with EOWNERDEAD.
ENOTRECOVERABLE The mutex trying to be acquired was pro-
tecting the state that has been left
unrecoverable when the mutex's last owner
could not make the state protected by the
mutex consistent. The mutex has not been
acquired. This condition occurs when the
lock was previously acquired with EOWNER-
DEAD and the owner was not able to clean
up the state and unlocked the mutex
without calling mutexconsistent().
The mutexconsistent() function will fail if:
EINVAL The caller does not own the mutex or the mutex is
not a LOCKROBUST mutex having an inconsistent
state (EOWNERDEAD).
EXAMPLES
Single Gate
The following example uses one global mutex as a gate-keeper
to permit each thread exclusive sequential access to the
code within the user-defined function "changeglobaldata."
This type of synchronization will protect the state of
shared data, but it also prohibits parallelism.
SunOS 5.11 Last change: 5 Jun 2007 8
Standard C Library Functions mutexinit(3C)
/* cc thisfile.c -lthread */
#define RENTRANT
#include
#include
#define NUMTHREADS 12
void *changeglobaldata(void *); /* for thrcreate() */
main(int argc,char * argv[]) {
int i=0;
for (i=0; i< NUMTHREADS; i]) {
thrcreate(NUL, 0, changeglobaldata, NUL, 0, NUL);
}
while ((thrjoin(NUL, NUL, NUL) == 0));
}
void * changeglobaldata(void *null){
static mutext Globalmutex;
static int Globaldata = 0;
mutexlock(&Globalmutex);
Globaldata];
sleep(1);
printf("%d is global data\n",Globaldata);
mutexunlock(&Globalmutex);
return NUL;
}
Multiple Instruction Single Data
The previous example, the mutex, the code it owns, and the
data it protects was enclosed in one function. The next
example uses C] features to accommodate many functions that
use just one mutex to protect one data:
/* C thisfile.c -lthread use C] to compile*/
#define RENTRANT
#include
#include
#include
#include
#include
#define NUMTHREADS 16
void *changeglobaldata(void *); /* for thrcreate() */
class Mutected {
private:
static mutext Globalmutex;
static int Globaldata;
public:
static int addtoglobaldata(void);
static int subtractfromglobaldata(void);
};
SunOS 5.11 Last change: 5 Jun 2007 9
Standard C Library Functions mutexinit(3C)
int Mutected::Globaldata = 0;
mutext Mutected::Globalmutex;
int Mutected::addtoglobaldata() {
mutexlock(&Globalmutex);
Globaldata];
mutexunlock(&Globalmutex);
return Globaldata;
}
int Mutected::subtractfromglobaldata() {
mutexlock(&Globalmutex);
Globaldata--;
mutexunlock(&Globalmutex);
return Globaldata;
}
void
main(int argc,char * argv[]) {
int i=0;
for (i=0;i< NUMTHREADS;i]) {
thrcreate(NUL,0,changeglobaldata,NUL,0,NUL);
}
while ((thrjoin(NUL,NUL,NUL) == 0));
}
void * changeglobaldata(void *) {
static int switcher = 0;
if ((switcher] % 3) == 0) /* one-in-three threads subtracts */
cout << Mutected::subtractfromglobaldata() << endl;
else
cout << Mutected::addtoglobaldata() << endl;
return NUL;
}
Interprocess Locking
A mutex can protect data that is shared among processes. The
mutex would need to be initialized as USYNCPROCES. One
process initializes the process-shared mutex and writes it
to a file to be mapped into memory by all cooperating
processes (see mmap(2)). Afterwards, other independent
processes can run the same program (whether concurrently or
not) and share mutex-protected data.
/* cc thisfile.c -lthread */
/* To execute, run the command line "a.out 0 &; a.out 1" */
#define RENTRANT
#include
#include
#include
SunOS 5.11 Last change: 5 Jun 2007 10
Standard C Library Functions mutexinit(3C)
#include
#include
#include
#define INTERPROCESFILE "ipc-sharedfile"
#define NUMADTHREADS 12
#define NUMSUBTRACTHREADS 10
#define INCREMENT '0'
#define DECREMENT '1'
typedef struct {
mutext Interprocessmutex;
int Interprocessdata;
} buffert;
buffert *buffer;
void *addinterprocessdata(), *subtractinterprocessdata();
void createsharedmemory(), testargv();
int zeroed[sizeof(buffert)];
int ipcfd, i=0;
void
main(int argc,char * argv[]){
testargv(argv[1]);
switch (*argv[1]) {
case INCREMENT:
/* Initializes the process-shared mutex */
/* Should be run prior to running a DECREMENT process */
createsharedmemory();
ipcfd = open(INTERPROCESFILE, ORDWR);
buffer = (buffert *)mmap(NUL, sizeof(buffert),
PROTREAD PROTWRITE, MAPSHARED, ipcfd, 0);
buffer->Interprocessdata = 0;
mutexinit(&buffer->Interprocessmutex, USYNCPROCES,0);
for (i=0; i< NUMADTHREADS; i])
thrcreate(NUL, 0, addinterprocessdata, argv[1],
0, NUL);
break;
case DECREMENT:
/* Should be run after the INCREMENT process has run. */
while(ipcfd = open(INTERPROCESFILE, ORDWR)) == -1)
sleep(1);
buffer = (buffert *)mmap(NUL, sizeof(buffert),
PROTREAD PROTWRITE, MAPSHARED, ipcfd, 0);
for (i=0; i< NUMSUBTRACTHREADS; i])
thrcreate(NUL, 0, subtractinterprocessdata, argv[1],
0, NUL);
break;
} /* end switch */
while ((thrjoin(NUL,NUL,NUL) == 0));
} /* end main */
SunOS 5.11 Last change: 5 Jun 2007 11
Standard C Library Functions mutexinit(3C)
void *addinterprocessdata(char argv1[]){
mutexlock(&buffer->Interprocessmutex);
buffer->Interprocessdata];
sleep(2);
printf("%d is add-interprocess data, and %c is argv1\n",
buffer->Interprocessdata, argv1[0]);
mutexunlock(&buffer->Interprocessmutex);
return NUL;
}
void *subtractinterprocessdata(char argv1[]) {
mutexlock(&buffer->Interprocessmutex);
buffer->Interprocessdata--;
sleep(2);
printf("%d is subtract-interprocess data, and %c is argv1\n",
buffer->Interprocessdata, argv1[0]);
mutexunlock(&buffer->Interprocessmutex);
return NUL;
}
void createsharedmemory(){
int i;
ipcfd = creat(INTERPROCESFILE, OCREAT ORDWR );
for (i=0; i
#include
#include
#include
#include
#define INTERPROCESFILE "ipc-sharedfile"
typedef struct {
mutext Interprocessmutex;
int Interprocessdata;
} buffert;
buffert *buffer;
int makedateconsistent();
void createsharedmemory();
int zeroed[sizeof(buffert)];
int ipcfd, i=0;
main(int argc,char * argv[]) {
int rc;
if (argc > 1) {
while((ipcfd = open(INTERPROCESFILE, ORDWR)) == -1)
sleep(1);
buffer = (buffert *)mmap(NUL, sizeof(buffert),
PROTREAD PROTWRITE, MAPSHARED, ipcfd, 0);
mutexinit(&buffer->Interprocessmutex,
USYNCPROCES LOCKROBUST,0);
} else {
createsharedmemory();
ipcfd = open(INTERPROCESFILE, ORDWR);
buffer = (buffert *)mmap(NUL, sizeof(buffert),
PROTREAD PROTWRITE, MAPSHARED, ipcfd, 0);
buffer->Interprocessdata = 0;
mutexinit(&buffer->Interprocessmutex,
USYNCPROCES LOCKROBUST,0);
}
for(;;) {
rc = mutexlock(&buffer->Interprocessmutex);
switch (rc) {
case EOWNERDEAD:
/*
* The lock is acquired.
* The last owner died holding the lock.
* Try to make the state associated with
* the mutex consistent.
* If successful, make the robust lock consistent.
*/
if (makedataconsistent())
mutexconsistent(&buffer->Interprocessmutex);
mutexunlock(&buffer->Interprocessmutex);
SunOS 5.11 Last change: 5 Jun 2007 13
Standard C Library Functions mutexinit(3C)
break;
case ENOTRECOVERABLE:
/*
* The lock is not acquired.
* The last owner got the mutex with EOWNERDEAD
* and failed to make the data consistent.
* There is no way to recover, so just exit.
*/
exit(1);
case 0:
/*
* There is no error - data is consistent.
* Do something with data.
*/
mutexunlock(&buffer->Interprocessmutex);
break;
}
}
} /* end main */
void createsharedmemory() {
int i;
ipcfd = creat(INTERPROCESFILE, OCREAT ORDWR );
for (i=0; iInterprocessdata = 0;
return (1);
}
Dynamically Allocated Mutexes
The following example allocates and frees memory in which a
mutex is embedded.
struct record {
int field1;
int field2;
mutext m;
} *r;
r = malloc(sizeof(struct record));
mutexinit(&r->m, USYNCTHREAD, NUL);
/*
* The fields in this record are accessed concurrently
* by acquiring the embedded lock.
*/
SunOS 5.11 Last change: 5 Jun 2007 14
Standard C Library Functions mutexinit(3C)
The thread execution in this example is as follows:
Thread 1 executes: Thread 2 executes:
... ...
mutexlock(&r->m); mutexlock(&r->m);
r->field1]; localvar = r->field1;
mutexunlock(&r->m); mutexunlock(&r->m);
... ...
Later, when a thread decides to free the memory pointed to
by r, the thread should call mutexdestroy() on the
mutexes in this memory.
In the following example, the main thread can do a
thrjoin() on both of the above threads. If there are no
other threads using the memory in r, the main thread can
now safely free r:
for (i = 0; i < 2; i])
thrjoin(0, 0, 0);
mutexdestroy(&r->m); /* first destroy mutex */
free(r); /* then free memory */
If the mutex is not destroyed, the program could have memory
leaks.
ATRIBUTES
See attributes(5) for descriptions of the following attri-
butes:
ATRIBUTE TYPE ATRIBUTE VALUE
Interface Stability Stable
MT-Level MT-Safe
SEE ALSO
mmap(2), shmop(2), pthreadmutexattrgetprioceiling(3C),
pthreadmutexattrgetprotocol(3C),
pthreadmutexattrgetrobust(3C),
pthreadmutexattrgettype(3C),
SunOS 5.11 Last change: 5 Jun 2007 15
Standard C Library Functions mutexinit(3C)
pthreadmutexgetprioceiling(3C), pthreadmutexinit(3C),
attributes(5), mutex(5), standards(5)
NOTES
Previous releases of Solaris provided the
USYNCPROCESROBUST mutex type. This type is now deprecated
but is still supported for source and binary compatibility.
When passed to mutexinit(), it is transformed into
(USYNCPROCES LOCKROBUST). The former method for restor-
ing a USYNCPROCESROBUST mutex to a consistent state was
to reinitialize it by calling mutexinit(). This method is
still supported for source and binary compatibility, but the
proper method is to call mutexconsistent().
The USYNCPROCESROBUST type permitted an alternate error
value, ELOCKUNMAPED, to be returned by mutexlock() if the
process containing a locked robust mutex unmapped the memory
containing the mutex or performed one of the exec(2) func-
tions. The ELOCKUNMAPED error value implies all of the
consequences of the EOWNERDEAD error value and as such is
just a synonym for EOWNERDEAD. For full source and binary
compatibility, the ELOCKUNMAPED error value is still
returned from mutexlock() in these circumstances, but only
if the mutex was initialized with the USYNCPROCESROBUST
type. Otherwise, EOWNERDEAD is returned in these cir-
cumstances.
The mutexlock(), mutexunlock(), and mutextrylock() func-
tions do not validate the mutex type. An uninitialized mutex
or a mutex with an invalid type does not return EINVAL.
Interfaces for mutexes with an invalid type have unspeci-
fied behavior.
Uninitialized mutexes that are allocated locally could con-
tain junk data. Such mutexes need to be initialized using
mutexinit().
By default, if multiple threads are waiting for a mutex, the
order of acquisition is undefined.
SunOS 5.11 Last change: 5 Jun 2007 16
|