trusty (3) pthread_mutex_destroy.3posix.gz

Provided by: manpages-posix-dev_2.16-1_all bug

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>

       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 .