|
739 | 739 | \begin{itemize} |
740 | 740 | \item Process synchronization is described on pages |
741 | 741 | \pageref{SYNCHRONIZATION} to \pageref{SYNCHRONIZATIONEND}. |
742 | | -\item Using mutexes and conditional variables it is possible to construct any |
| 742 | +\item By using mutexes and conditional variables it is possible to construct any |
743 | 743 | other synchronization model. |
744 | 744 | \item The exact behavior of synchronization primitives is largely determined by |
745 | | -the scheduler, that decides which of the threads waiting for unlock will be |
746 | | -waked up after the unlock happens. This leads to classical problems such as |
747 | | -\emph{thundering horde} (lots of threads waiting for unlock) |
748 | | -or \emph{priority inversion} (thread holding a lock has lower priority than |
| 745 | +the scheduler. It decides which of the threads waiting for releasing a lock |
| 746 | +will be woken up after the lock is actually released. This leads to classical |
| 747 | +problems such as a \emph{thundering horde} (lots of threads waiting for unlock) |
| 748 | +or a \emph{priority inversion} (thread holding a lock has lower priority than |
749 | 749 | the thread waiting for the lock). |
750 | 750 | \end{itemize} |
751 | 751 |
|
|
794 | 794 | when acquiring it, it is necessary to test return value of |
795 | 795 | \texttt{p\-thread\_mutex\_lock}, and also have the lock checking set, see below. |
796 | 796 | \item Mutexes are meant to be held for short time only. They are used for |
797 | | -critical section (see the definition on page \pageref{CRITICALSECTION}), |
798 | | -implementation, similarly to lock-files or semaphores (used like locks). |
799 | | -\item Lock checking is governed by mutex type. By default the mutex type is set to |
800 | | -\texttt{PTHREAD\_MUTEX\_DEF\-AULT}. This type does not define the result of |
801 | | -locking a locked mutex, unlocking a mutex locked by different thread or |
802 | | -unlocking an unlocked mutex. Concrete Unix implementations will map this define |
803 | | -to \texttt{PTHREAD\_MUTEX\_NORMAL} or \texttt{PTHREAD\_\-MUT\-EX\_ERRORCHECK}. |
804 | | -Thus, depending on correct implementation, that locking already locked mutex |
805 | | -will result in deadlock (\texttt{NORMAL}) or not (\texttt{ERRORCHECK}). |
806 | | -In the second case, return value will contain information about the error. |
807 | | -If not tested, the program will wrongly assume that the mutex is locked. |
808 | | -For the \texttt{NORMAL} type the result of the remaining two situations is not |
809 | | -defined, for \texttt{ERRORCHECK} an error will be returned. ``Not defined`` |
810 | | -means that the thread unlocking a mutex locked by different thread can succeed. |
811 | | -Or not -- everything depends on the implementation at hand. It also means that |
812 | | -the result of such operations is of no interest because these should be avoided. |
813 | | -More info can be found in the POSIX standard or the |
814 | | -\texttt{pth\-read\_mutex\-attr\_set\-ty\-pe} man page. |
815 | | -Checking return values of mutex functions can make the code slightly less |
816 | | -readable however it can be wrapped in a macro. Alternatively, the checks can be |
817 | | -used during development only. |
818 | | -Solaris and Linux use \texttt{NORMAL} type by default, FreeBSD uses |
819 | | -\texttt{ERRORCHECK}. |
820 | | -\label{NOTMYLOCK} |
| 797 | +critical section (see the definition on page \pageref{CRITICALSECTION}) |
| 798 | +implementation, similarly to lock-files or semaphores (if used like locks). |
| 799 | +\item Lock checking is governed by a mutex type. By default the mutex type is |
| 800 | +set to \texttt{PTHREAD\_MUTEX\_DEF\-AULT}. This type by itself does not define |
| 801 | +the result of (a) locking a locked mutex, (b) unlocking a mutex locked by a |
| 802 | +different thread, or (c) unlocking an unlocked mutex. Unix/Linux systems will |
| 803 | +map that macro to \texttt{PTHREAD\_MUTEX\_NORMAL} or |
| 804 | +\texttt{PTHREAD\_\-MUT\-EX\_ERRORCHECK} (ignoring the recursive type, see |
| 805 | +below). Thus, depending on a specific system, locking an already locked mutex |
| 806 | +will result in a deadlock (\texttt{NORMAL}) or not (\texttt{ERRORCHECK}). In |
| 807 | +the latter case, a return value will contain information about the error and if |
| 808 | +not tested, the program will wrongly assume the mutex is locked. For the |
| 809 | +\texttt{NORMAL} mutex type the result of (b) and (c) is not |
| 810 | +defined, for \texttt{ERRORCHECK} an error will be returned. |
| 811 | +In general you should avoid any undefined behavior unless specifically |
| 812 | +documented by the system at hand. More information can be found in the POSIX |
| 813 | +standard or the \texttt{pth\-read\_mutex\-attr\_set\-ty\-pe} man page. Checking |
| 814 | +return values of mutex functions can make the code slightly less readable |
| 815 | +however it can be wrapped in a macro. Alternatively, the checks can be used |
| 816 | +during development only. Solaris and Linux use \texttt{NORMAL} type by default, |
| 817 | +FreeBSD uses \texttt{ERRORCHECK}. \label{NOTMYLOCK} |
821 | 818 | Example: \example{mutexes/not-my-lock.c}. |
822 | | -\item Another type is \texttt{PTHREAD\_MUTEX\_RECURSIVE} that holds count of |
| 819 | +\item Another type is \texttt{PTHREAD\_MUTEX\_RECURSIVE} that holds a count of |
823 | 820 | lock actions done by given thread. The remaining threads will be granted access |
824 | 821 | only if the count reaches 0. This mutex cannot be shared between processes. |
825 | | -\item What are recursive mutexes good for ? Let's assume there are two |
| 822 | +\item What are recursive mutexes good for? Let's assume there are two |
826 | 823 | libraries, \texttt{A} and \texttt{B}. There is a library |
827 | | -function \texttt{A:foo()}, that will acquire a mutex and calls \texttt{B:bar()} |
828 | | -that can in turn call \texttt{A:bar()}, which will try to acquire the same |
829 | | -mutex. Without recursive locks a deadlock will ensue. With recursive mutexes |
| 824 | +function \texttt{A:foo()} acquires a mutex and calls \texttt{B:bar()}, |
| 825 | +and in turn calls \texttt{A:bar()} which tries to acquire the same |
| 826 | +mutex. Without recursive locks a deadlock will ensue. With recursive mutexes |
830 | 827 | that's fine if these two calls are done by the same thread (another thread will |
831 | | -get blocked). That is, assuming \texttt{A:foo()} and \texttt{A:bar()} are aware |
| 828 | +get blocked). That is, assuming \texttt{A:foo()} and \texttt{A:bar()} are aware |
832 | 829 | that the same thread can be already in the critical section. |
833 | 830 | \item \label{MUTEXTAB} The behavior according to mutex types:\\ |
834 | 831 | \\ |
|
849 | 846 | allocated mutex. If a mutex is dynamically allocated, it is always necessary to |
850 | 847 | use \texttt{pthread\_mutex\_init}, even if the default attributes are desired or |
851 | 848 | not. |
852 | | -\item Dynamic mutexes are needed e.g. when a data structure which contains a |
853 | | -mutex protecting it, is dynamically allocated. |
854 | | -In such case before calling \texttt{free} with the data structure, it is first |
855 | | -necessary to properly destroy the mutex (that can also have some memory |
856 | | -allocated). Destroying locked mutex is not defined by the standard. |
| 849 | +\item Dynamic mutexes are needed e.g. when a data structure containing a mutex |
| 850 | +protecting it is dynamically allocated. In such a case, before calling |
| 851 | +\texttt{free} with the data structure, it is first necessary to properly destroy |
| 852 | +the mutex (that can also have some memory allocated). Destroying a locked mutex |
| 853 | +is not defined by the standard. |
857 | 854 | \item Copying mutexes is also not defined by the standard -- the result of such |
858 | | -operation depends on implementation. It is possible to copy pointer to mutex |
859 | | -and work with that. |
860 | | -\item Mutex destroy means its deinitialization. |
| 855 | +an operation depends on the implementation. It is possible to copy a pointer to |
| 856 | +a mutex and work with that. |
| 857 | +\item A mutex destroy means its deinitialization. |
861 | 858 | \end{itemize} |
862 | 859 |
|
863 | 860 | %%%%% |
|
899 | 896 | \begin{itemize} |
900 | 897 | \item Locking a mutex that is being held by another thread is not correct. |
901 | 898 | Sometimes a (self)deadlock can ensue, see the previous page. If you need to |
902 | | -unlock a mutex locked by different thread, use binary semaphores instead. |
| 899 | +unlock a mutex locked by a different thread, use binary semaphores instead. |
903 | 900 | \item When creating a program where efficiency is paramount, it is necessary to |
904 | | -think about how many mutexes will be needed and how exactly will be used. |
| 901 | +think about how many mutexes will be needed and how exactly they will be used. |
905 | 902 | Even a library that was not written with threads in mind can be converted to be |
906 | | -thread-safe (see page \pageref{THREADSAFE}) by inserting arbitrary function from |
907 | | -the library a lock will be acquired and released before the function exits. |
908 | | -Such locked can be called ``giant'' mutex, i.e. there will be lock contention |
909 | | -for every consumer of such library in given program. On the other hand, if using |
910 | | -many mutexes to synchronize access to concrete small sections, lots of time can |
911 | | -be spent in the functions implementing the locking. It is therefore desired to |
912 | | -search for a compromise. (Or use an algorithm that does not require locks at |
913 | | -all) |
| 903 | +thread-safe (see page \pageref{THREADSAFE}) by acquiring a per-library lock on |
| 904 | +any library function entry and releasing the lock before the function exits. |
| 905 | +Such a lock may be called a ``giant'' mutex, and it may lead to lock contention |
| 906 | +for every consumer of such a library as at any given moment only one thread may |
| 907 | +execute the library code. On the other hand, if using a large number of mutexes |
| 908 | +to synchronize access to many small sections, significant amount of time might |
| 909 | +be spent in the overhead of calling functions implementing the locking. It is |
| 910 | +therefore desired to search for a compromise. (Or use an algorithm that does |
| 911 | +not require locks at all). |
914 | 912 | \item \label{MUTEX_RACE} Examples: \example{mutexes/race.c}, |
915 | 913 | \example{mutexes/race-fixed.c} |
916 | 914 | \item Mutexes can be shared between processes so that their threads will |
|
0 commit comments