|
From: <sv...@va...> - 2008-10-11 18:28:20
|
Author: bart Date: 2008-10-11 19:28:12 +0100 (Sat, 11 Oct 2008) New Revision: 8656 Log: Added paragraph "Using the POSIX Threads API Effectively." Modified: trunk/drd/docs/drd-manual.xml Modified: trunk/drd/docs/drd-manual.xml =================================================================== --- trunk/drd/docs/drd-manual.xml 2008-10-11 18:04:52 UTC (rev 8655) +++ trunk/drd/docs/drd-manual.xml 2008-10-11 18:28:12 UTC (rev 8656) @@ -993,12 +993,12 @@ following to your shell startup script: </para> <programlisting><![CDATA[ -export LD_LIBRARY_PATH=~/gcc-4.3.1/lib64:~/gcc-4.3.1/lib: +export LD_LIBRARY_PATH=~/gcc-4.3.2/lib64:~/gcc-4.3.2/lib: ]]></programlisting> <para> As an example, the test OpenMP test program -<literal>drd/scripts/omp_matinv</literal> triggers a data race +<literal>drd/tests/omp_matinv</literal> triggers a data race when the option -r has been specified on the command line. The data race is triggered by the following code: </para> @@ -1046,7 +1046,7 @@ <para> Note: DRD reports errors on the <literal>libgomp</literal> library -included with gcc 4.2.0 up to and including 4.3.1. This might indicate +included with gcc 4.2.0 up to and including 4.3.2. This might indicate a race condition in the POSIX version of <literal>libgomp</literal>. </para> @@ -1238,6 +1238,165 @@ </sect1> +<sect1 id="drd-manual.Pthreads" xreflabel="Pthreads"> +<title>Using the POSIX Threads API Effectively</title> + +<sect2 id="drd-manual.mutex-types" xreflabel="mutex-types"> +<title>Mutex types</title> + +<para> +The Single UNIX Specification version two defines the following four +mutex types (see also the documentation of <ulink +url="http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_mutexattr_settype.html"><function>pthread_mutexattr_settype()</function></ulink>): +<itemizedlist> + <listitem> + <para> + <emphasis>normal</emphasis>, which means that no error checking + is performed, and that the mutex is non-recursive. + </para> + </listitem> + <listitem> + <para> + <emphasis>error checking</emphasis>, which means that the mutex + is non-recursive and that error checking is performed. + </para> + </listitem> + <listitem> + <para> + <emphasis>recursive</emphasis>, which means that a mutex may be + locked recursively. + </para> + </listitem> + <listitem> + <para> + <emphasis>default</emphasis>, which means that error checking + behavior is undefined, and that the behavior for recursive + locking is also undefined. Or: portable code must neither + trigger error conditions through the Pthreads API nor attempt to + lock a mutex of default type recursively. + </para> + </listitem> +</itemizedlist> +</para> + +<para> +In complex applications it is not always clear from beforehand which +mutex will be locked recursively and which mutex will not be locked +recursively. Attempts lock a non-recursive mutex recursively will +result in race conditions that are very hard to find without a thread +checking tool. So either use the error checking mutex type and +consistently check the return value of Pthread API mutex calls, or use +the recursive mutex type. +</para> + +</sect2> + +<sect2 id="drd-manual.condvar" xreflabel="condition-variables"> +<title>Condition variables</title> + +<para> +A condition variable allows one thread to wake up one or more other +threads. Condition variables are typically used to notify one or more +threads about state changes of shared data. Unfortunately it is very +easy to introduce race conditions by using condition variables as the +only means of state information propagation. A better approach is to +let threads poll for changes of a state variable that is protected by +a mutex, and to use condition variables only as a thread wakeup +mechanism. See also the source file +<computeroutput>drd/tests/monitor_example.cpp</computeroutput> for an +example of how to implement this concept in C++. The monitor concept +used in this example is a well known concept in computer science -- +see also Wikipedia for more information about the <ulink +url="http://en.wikipedia.org/wiki/Monitor_(synchronization)">monitor</ulink> +concept. +</para> + +</sect2> + +<sect2 id="drd-manual.pctw" xreflabel="pthread_cond_timedwait"> +<title>pthread_cond_timedwait() and timeouts</title> + +<para> +Historically the function +<function>pthread_cond_timedwait()</function> only allowed the +specification of an absolute timeout, that is a timeout independent of +the time when this function was called. However, almost every call to +this function expresses a relative timeout. This typically happens by +passing the sum of +<computeroutput>clock_gettime(CLOCK_REALTIME)</computeroutput> and a +relative timeout as the third argument. This approach is incorrect +since forward or backward clock adjustments by e.g. ntpd will affect +the timeout. A more reliable approach is as follows: +<itemizedlist> + <listitem> + <para> + When initializing a condition variable through + pthread_cond_init(), specify that the timeout of + pthread_cond_timedwait() will use the clock + <literal>CLOCK_MONOTONIC</literal> instead of + <literal>CLOCK_REALTIME</literal>. You can do this via + <computeroutput>pthread_condattr_setclock(..., + CLOCK_MONOTONIC)</computeroutput>. See also + <computeroutput>drd/tests/monitor_example.cpp</computeroutput> + for an example. + </para> + </listitem> + <listitem> + <para> + When calling <function>pthread_cond_timedwait()</function>, pass + the sum of + <computeroutput>clock_gettime(CLOCK_MONOTONIC)</computeroutput> + and a relative timeout as the third argument. + </para> + </listitem> +</itemizedlist> +</para> + +</sect2> + +<sect2 id="drd-manual.naming-threads" xreflabel="naming threads"> +<title>Assigning names to threads</title> + +<para> +Many applications log information about changes in internal or +external state to a file. When analyzing log files of a multithreaded +application it can be very convenient to know which thread logged +which information. One possible approach is to identify threads in +logging output by including the result of +<function>pthread_self()</function> in every log line. However, this approach +has two disadvantages: there is no direct relationship between these +values and the source code and these values can be different in each +run. A better approach is to assign a brief name to each thread and to +include the assigned thread name in each log line. One possible +approach for managing thread names is as follows: +<itemizedlist> + <listitem> + <para> + Allocate a key for the pointer to the thread name through + <function>pthread_key_create()</function>. + </para> + </listitem> + <listitem> + <para> + Just after thread creation, set the thread name through + <function>pthread_setspecific()</function>. + </para> + </listitem> + <listitem> + <para> + In the code that generates the logging information, query the thread + name by calling <function>pthread_getspecific()</function>. + </para> + </listitem> +</itemizedlist> + +</para> + +</sect2> + +</sect1> + + <sect1 id="drd-manual.limitations" xreflabel="Limitations"> <title>Limitations</title> |