PTHREAD_MUTEX_DESTROY(3P) POSIX Programmer's Manual PTHREAD_MUTEX_DESTROY(3P)
PROLOG
This manual page is part of the POSIX Programmer's Manual. The Linux
implementation of this interface may differ (consult the corresponding
Linux manual page for details of Linux behavior), or the interface may
not be implemented on Linux.
NAME
pthread_mutex_destroy, pthread_mutex_init -- destroy and initialize a
mutex
SYNOPSIS
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
DESCRIPTION
The pthread_mutex_destroy() function shall destroy the mutex object
referenced by mutex; the mutex object becomes, in effect, uninitial-
ized. An implementation may cause pthread_mutex_destroy() to set the
object referenced by mutex to an invalid value.
A destroyed mutex object can be reinitialized using
pthread_mutex_init(); the results of otherwise referencing the object
after it has been destroyed are undefined.
It shall be safe to destroy an initialized mutex that is unlocked.
Attempting to destroy a locked mutex or a mutex that is referenced (for
example, while being used in a pthread_cond_timedwait() or
pthread_cond_wait()) by another thread results in undefined behavior.
The pthread_mutex_init() function shall initialize the mutex referenced
by mutex with attributes specified by attr. If attr is NULL, the
default mutex attributes are used; the effect shall be the same as
passing the address of a default mutex attributes object. Upon success-
ful initialization, the state of the mutex becomes initialized and
unlocked.
Only mutex itself may be used for performing synchronization. The
result of referring to copies of mutex in calls to
pthread_mutex_lock(), pthread_mutex_trylock(), pthread_mutex_unlock(),
and pthread_mutex_destroy() is undefined.
Attempting to initialize an already initialized mutex results in unde-
fined behavior.
In cases where default mutex attributes are appropriate, the macro
PTHREAD_MUTEX_INITIALIZER can be used to initialize mutexes. The effect
shall be equivalent to dynamic initialization by a call to
pthread_mutex_init() with parameter attr specified as NULL, except that
no error checks are performed.
The behavior is undefined if the value specified by the mutex argument
to pthread_mutex_destroy() does not refer to an initialized mutex.
The behavior is undefined if the value specified by the attr argument
to pthread_mutex_init() does not refer to an initialized mutex
attributes object.
RETURN VALUE
If successful, the pthread_mutex_destroy() and pthread_mutex_init()
functions shall return zero; otherwise, an error number shall be
returned to indicate the error.
ERRORS
The pthread_mutex_init() function shall fail if:
EAGAIN The system lacked the necessary resources (other than memory) to
initialize another mutex.
ENOMEM Insufficient memory exists to initialize the mutex.
EPERM The caller does not have the privilege to perform the operation.
The pthread_mutex_init() function may fail if:
EINVAL The attributes object referenced by attr has the robust mutex
attribute set without the process-shared attribute being set.
These functions shall not return an error code of [EINTR].
The following sections are informative.
EXAMPLES
None.
APPLICATION USAGE
None.
RATIONALE
If an implementation detects that the value specified by the mutex
argument to pthread_mutex_destroy() does not refer to an initialized
mutex, it is recommended that the function should fail and report an
[EINVAL] error.
If an implementation detects that the value specified by the mutex
argument to pthread_mutex_destroy() or pthread_mutex_init() refers to a
locked mutex or a mutex that is referenced (for example, while being
used in a pthread_cond_timedwait() or pthread_cond_wait()) by another
thread, or detects that the value specified by the mutex argument to
pthread_mutex_init() refers to an already initialized mutex, it is rec-
ommended that the function should fail and report an [EBUSY] error.
If an implementation detects that the value specified by the attr argu-
ment to pthread_mutex_init() does not refer to an initialized mutex
attributes object, it is recommended that the function should fail and
report an [EINVAL] error.
Alternate Implementations Possible
This volume of POSIX.1-2008 supports several alternative implementa-
tions of mutexes. An implementation may store the lock directly in the
object of type pthread_mutex_t. Alternatively, an implementation may
store the lock in the heap and merely store a pointer, handle, or
unique ID in the mutex object. Either implementation has advantages or
may be required on certain hardware configurations. So that portable
code can be written that is invariant to this choice, this volume of
POSIX.1-2008 does not define assignment or equality for this type, and
it uses the term ``initialize'' to reinforce the (more restrictive)
notion that the lock may actually reside in the mutex object itself.
Note that this precludes an over-specification of the type of the mutex
or condition variable and motivates the opaqueness of the type.
An implementation is permitted, but not required, to have
pthread_mutex_destroy() store an illegal value into the mutex. This may
help detect erroneous programs that try to lock (or otherwise refer-
ence) a mutex that has already been destroyed.
Tradeoff Between Error Checks and Performance Supported
Many error conditions that can occur are not required to be detected by
the implementation in order to let implementations trade off perfor-
mance versus degree of error checking according to the needs of their
specific applications and execution environment. As a general rule,
conditions caused by the system (such as insufficient memory) are
required to be detected, but conditions caused by an erroneously coded
application (such as failing to provide adequate synchronization to
prevent a mutex from being deleted while in use) are specified to
result in undefined behavior.
A wide range of implementations is thus made possible. For example, an
implementation intended for application debugging may implement all of
the error checks, but an implementation running a single, provably cor-
rect application under very tight performance constraints in an embed-
ded computer might implement minimal checks. An implementation might
even be provided in two versions, similar to the options that compilers
provide: a full-checking, but slower version; and a limited-checking,
but faster version. To forbid this optionality would be a disservice to
users.
By carefully limiting the use of ``undefined behavior'' only to things
that an erroneous (badly coded) application might do, and by defining
that resource-not-available errors are mandatory, this volume of
POSIX.1-2008 ensures that a fully-conforming application is portable
across the full range of implementations, while not forcing all imple-
mentations to add overhead to check for numerous things that a correct
program never does. When the behavior is undefined, no error number is
specified to be returned on implementations that do detect the condi-
tion. This is because undefined behavior means anything can happen,
which includes returning with any value (which might happen to be a
valid, but different, error number). However, since the error number
might be useful to application developers when diagnosing problems dur-
ing application development, a recommendation is made in rationale that
implementors should return a particular error number if their implemen-
tation does detect the condition.
Why No Limits are Defined
Defining symbols for the maximum number of mutexes and condition vari-
ables was considered but rejected because the number of these objects
may change dynamically. Furthermore, many implementations place these
objects into application memory; thus, there is no explicit maximum.
Static Initializers for Mutexes and Condition Variables
Providing for static initialization of statically allocated synchro-
nization objects allows modules with private static synchronization
variables to avoid runtime initialization tests and overhead. Further-
more, it simplifies the coding of self-initializing modules. Such mod-
ules are common in C libraries, where for various reasons the design
calls for self-initialization instead of requiring an explicit module
initialization function to be called. An example use of static initial-
ization follows.
Without static initialization, a self-initializing routine foo() might
look as follows:
static pthread_once_t foo_once = PTHREAD_ONCE_INIT;
static pthread_mutex_t foo_mutex;
void foo_init()
{
pthread_mutex_init(&foo_mutex, NULL);
}
void foo()
{
pthread_once(&foo_once, foo_init);
pthread_mutex_lock(&foo_mutex);
/* Do work. */
pthread_mutex_unlock(&foo_mutex);
}
With static initialization, the same routine could be coded as follows:
static pthread_mutex_t foo_mutex = PTHREAD_MUTEX_INITIALIZER;
void foo()
{
pthread_mutex_lock(&foo_mutex);
/* Do work. */
pthread_mutex_unlock(&foo_mutex);
}
Note that the static initialization both eliminates the need for the
initialization test inside pthread_once() and the fetch of &foo_mutex
to learn the address to be passed to pthread_mutex_lock() or
pthread_mutex_unlock().
Thus, the C code written to initialize static objects is simpler on all
systems and is also faster on a large class of systems; those where the
(entire) synchronization object can be stored in application memory.
Yet the locking performance question is likely to be raised for
machines that require mutexes to be allocated out of special memory.
Such machines actually have to have mutexes and possibly condition
variables contain pointers to the actual hardware locks. For static
initialization to work on such machines, pthread_mutex_lock() also has
to test whether or not the pointer to the actual lock has been allo-
cated. If it has not, pthread_mutex_lock() has to initialize it before
use. The reservation of such resources can be made when the program is
loaded, and hence return codes have not been added to mutex locking and
condition variable waiting to indicate failure to complete initializa-
tion.
This runtime test in pthread_mutex_lock() would at first seem to be
extra work; an extra test is required to see whether the pointer has
been initialized. On most machines this would actually be implemented
as a fetch of the pointer, testing the pointer against zero, and then
using the pointer if it has already been initialized. While the test
might seem to add extra work, the extra effort of testing a register is
usually negligible since no extra memory references are actually done.
As more and more machines provide caches, the real expenses are memory
references, not instructions executed.
Alternatively, depending on the machine architecture, there are often
ways to eliminate all overhead in the most important case: on the lock
operations that occur after the lock has been initialized. This can be
done by shifting more overhead to the less frequent operation: initial-
ization. Since out-of-line mutex allocation also means that an address
has to be dereferenced to find the actual lock, one technique that is
widely applicable is to have static initialization store a bogus value
for that address; in particular, an address that causes a machine fault
to occur. When such a fault occurs upon the first attempt to lock such
a mutex, validity checks can be done, and then the correct address for
the actual lock can be filled in. Subsequent lock operations incur no
extra overhead since they do not ``fault''. This is merely one tech-
nique that can be used to support static initialization, while not
adversely affecting the performance of lock acquisition. No doubt there
are other techniques that are highly machine-dependent.
The locking overhead for machines doing out-of-line mutex allocation is
thus similar for modules being implicitly initialized, where it is
improved for those doing mutex allocation entirely inline. The inline
case is thus made much faster, and the out-of-line case is not signifi-
cantly worse.
Besides the issue of locking performance for such machines, a concern
is raised that it is possible that threads would serialize contending
for initialization locks when attempting to finish initializing stati-
cally allocated mutexes. (Such finishing would typically involve taking
an internal lock, allocating a structure, storing a pointer to the
structure in the mutex, and releasing the internal lock.) First, many
implementations would reduce such serialization by hashing on the mutex
address. Second, such serialization can only occur a bounded number of
times. In particular, it can happen at most as many times as there are
statically allocated synchronization objects. Dynamically allocated
objects would still be initialized via pthread_mutex_init() or
pthread_cond_init().
Finally, if none of the above optimization techniques for out-of-line
allocation yields sufficient performance for an application on some
implementation, the application can avoid static initialization alto-
gether by explicitly initializing all synchronization objects with the
corresponding pthread_*_init() functions, which are supported by all
implementations. An implementation can also document the tradeoffs and
advise which initialization technique is more efficient for that par-
ticular implementation.
Destroying Mutexes
A mutex can be destroyed immediately after it is unlocked. For example,
consider the following code:
struct obj {
pthread_mutex_t om;
int refcnt;
...
};
obj_done(struct obj *op)
{
pthread_mutex_lock(&op->om);
if (--op->refcnt == 0) {
pthread_mutex_unlock(&op->om);
(A) pthread_mutex_destroy(&op->om);
(B) free(op);
} else
(C) pthread_mutex_unlock(&op->om);
}
In this case obj is reference counted and obj_done() is called whenever
a reference to the object is dropped. Implementations are required to
allow an object to be destroyed and freed and potentially unmapped (for
example, lines A and B) immediately after the object is unlocked (line
C).
Robust Mutexes
Implementations are required to provide robust mutexes for mutexes with
the process-shared attribute set to PTHREAD_PROCESS_SHARED. Implementa-
tions are allowed, but not required, to provide robust mutexes when the
process-shared attribute is set to PTHREAD_PROCESS_PRIVATE.
FUTURE DIRECTIONS
None.
SEE ALSO
pthread_mutex_getprioceiling(), pthread_mutexattr_getrobust(),
pthread_mutex_lock(), pthread_mutex_timedlock(), pthread_mutex-
attr_getpshared()
The Base Definitions volume of POSIX.1-2008, <pthread.h>
COPYRIGHT
Portions of this text are reprinted and reproduced in electronic form
from IEEE Std 1003.1, 2013 Edition, Standard for Information Technology
-- Portable Operating System Interface (POSIX), The Open Group Base
Specifications Issue 7, Copyright (C) 2013 by the Institute of Electri-
cal and Electronics Engineers, Inc and The Open Group. (This is
POSIX.1-2008 with the 2013 Technical Corrigendum 1 applied.) In the
event of any discrepancy between this version and the original IEEE and
The Open Group Standard, the original IEEE and The Open Group Standard
is the referee document. The original Standard can be obtained online
at http://www.unix.org/online.html .
Any typographical or formatting errors that appear in this page are
most likely to have been introduced during the conversion of the source
files to man page format. To report such errors, see https://www.ker-
nel.org/doc/man-pages/reporting_bugs.html .
IEEE/The Open Group 2013 PTHREAD_MUTEX_DESTROY(3P)