Man Linux: Main Page and Category List

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,
       uninitialized. 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 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
       successful  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
       undefined behavior.

       In cases where default mutex  attributes  are  appropriate,  the  macro
       PTHREAD_MUTEX_INITIALIZER  can  be  used to initialize mutexes that are
       statically  allocated.  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.

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.

       The [EBUSY] and [EINVAL] error checks, if implemented, act as  if  they
       were  performed  immediately  at  the  beginning  of processing for the
       function and shall cause an error return prior to modifying  the  state
       of the mutex specified by mutex.

ERRORS

       The pthread_mutex_destroy() function may fail if:

       EBUSY  The implementation has detected an attempt to destroy the object
              referenced by mutex  while  it  is  locked  or  referenced  (for
              example,  while  being  used  in  a  pthread_cond_timedwait() or
              pthread_cond_wait()) by another thread.

       EINVAL The value specified by mutex is invalid.

       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:

       EBUSY  The implementation has detected an attempt to  reinitialize  the
              object  referenced  by  mutex, a previously initialized, but not
              yet destroyed, mutex.

       EINVAL The value specified by attr is invalid.

       These functions shall not return an error code of [EINTR].

       The following sections are informative.

EXAMPLES

       None.

APPLICATION USAGE

       None.

RATIONALE

   Alternate Implementations Possible
       This  volume  of  IEEE Std 1003.1-2001  supports  several   alternative
       implementations  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 IEEE Std 1003.1-2001 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
       reference) a mutex that has already been destroyed.

   Tradeoff Between Error Checks and Performance Supported
       Many  of  the  error  checks  were  made  optional  in  order  to   let
       implementations  trade  off performance versus degree of error checking
       according to the needs of their  specific  applications  and  execution
       environment.  As  a  general  rule,  errors or conditions caused by the
       system (such as insufficient memory) always need to  be  reported,  but
       errors  due  to  an  erroneously  coded application (such as failing to
       provide adequate synchronization to prevent a mutex from being  deleted
       while in use) are made optional.

       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
       correct application under very  tight  performance  constraints  in  an
       embedded  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
       IEEE Std 1003.1-2001 ensures that  a  fully-conforming  application  is
       portable  across  the  full range of implementations, while not forcing
       all implementations to add overhead to check for numerous things that a
       correct program never does.

   Why No Limits are Defined
       Defining  symbols  for  the  maximum  number  of  mutexes and condition
       variables 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
       synchronization   objects   allows   modules   with   private    static
       synchronization  variables  to  avoid  runtime initialization tests and
       overhead. Furthermore, it simplifies the  coding  of  self-initializing
       modules.  Such  modules  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 initialization 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
       allocated.  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
       initialization.

       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:
       initialization.  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 technique 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
       significantly 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
       statically 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
       altogether  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
       particular 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).

FUTURE DIRECTIONS

       None.

SEE ALSO

       pthread_mutex_getprioceiling()      ,      pthread_mutex_lock()       ,
       pthread_mutex_timedlock()  ,  pthread_mutexattr_getpshared() , the Base
       Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

COPYRIGHT

       Portions of this text are reprinted and reproduced in  electronic  form
       from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology
       -- Portable Operating System Interface (POSIX),  The  Open  Group  Base
       Specifications  Issue  6,  Copyright  (C) 2001-2003 by the Institute of
       Electrical and Electronics Engineers, Inc and The Open  Group.  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.opengroup.org/unix/online.html .