Pthreads: Difference between revisions

 
(4 intermediate revisions by the same user not shown)
Line 7: Line 7:
* The Triforce of POSIX Thread stacks:
* The Triforce of POSIX Thread stacks:
** If you aren't allocating a stack fit to your thread, you will one day smash that stack.
** If you aren't allocating a stack fit to your thread, you will one day smash that stack.
** If you're using your stack, you should probably heap-allocate or use TLS.
** If you're using your stack, you should probably heap-allocate or use [[TLS]].
** Recursion's all fun and games until your recurse on through to the other side.
** Recursion's all fun and games until your recurse on through to the other side.
** Yes, this all applies to an unthreaded program (especially an embedded one), with a critical difference -- memory management is process-based, causing noisy failures in the unthreaded case. Meanwhile, a POSIX thread will happily push a frame down right over his buddy's DTV/TLS in NPTL (see [http://www.redhat.com/whitepapers/developer/POSIX_Linux_Threading.pdf NPTL], "Memory Allocation"). Have a good time debugging that, champ!
** Yes, this all applies to an unthreaded program (especially an embedded one), with a critical difference -- memory management is process-based, causing noisy failures in the unthreaded case. Meanwhile, a POSIX thread will happily push a frame down right over his buddy's DTV/[[TLS]] in NPTL (see [http://www.redhat.com/whitepapers/developer/POSIX_Linux_Threading.pdf NPTL], "Memory Allocation"). Have a good time debugging that, champ!
* Failure to check every return, especially pthread_mutex_destroy(), is cause for [http://en.wikipedia.org/wiki/Tuol_Sleng_Genocide_Museum#The_Security_Regulations many many lashes of electric wire].
* Failure to check every return, especially pthread_mutex_destroy(), is cause for [http://en.wikipedia.org/wiki/Tuol_Sleng_Genocide_Museum#The_Security_Regulations many many lashes of electric wire].
* Those who fail to designate an alternate signal stack will one day wish they had.
* Those who fail to designate an alternate signal stack will one day wish they had.
Line 20: Line 20:
* Before trying to solve an issue with POSIX thread scheduling parameters, see if you can't just drink some hydrochloric acid.
* Before trying to solve an issue with POSIX thread scheduling parameters, see if you can't just drink some hydrochloric acid.
* No, you shouldn't be using the [http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt volatile keyword].
* No, you shouldn't be using the [http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt volatile keyword].
==Condition variable clocks==
By default, <tt>pthread_cond_timedwait()</tt> uses <tt>CLOCK_REALTIME</tt>, with all its attendant problems. You probably want it to use <tt>CLOCK_MONOTONIC</tt>. This can be effected on some implementations using <tt>pthread_condattr_setclock()</tt>. The new function <tt>pthread_cond_clockwait()</tt> has been [https://www.austingroupbugs.net/view.php?id=1216 proposed], but not yet accepted into the POSIX standard. Note that C++'s <tt>std::condition_variable</tt> also [https://reviews.llvm.org/D65339 suffers] from this braindamage.


==Pthreads signal model==
==Pthreads signal model==
POSIX threads specify that all threads within a process share a PID, and that each has its own, distinct thread id. PIDs have the integer type <tt>pid_t</tt>, and only positive PIDs can define actual processes. TIDs have the opaque type <tt>pthread_t</tt>; they cannot be ordered, but can be compared for equality.
POSIX threads specify that all threads within a process share a PID, and that each has its own, distinct thread id. PIDs have the integer type <tt>pid_t</tt>, and only positive PIDs can define actual processes. TIDs have the opaque type <tt>pthread_t</tt>; they cannot be ordered, but can be compared for equality.


Other processes can direct signals only to a PID, not the thread IDs within another process (TIDs of a given process have no meaning outside that process). Within the process, signals can be directed to particular TIDs. Use of <tt>raise(s)</tt> in a threaded program is equivalent to <tt>pthread_kill(pthread_self(),s)</tt>.
Other processes can direct signals only to a PID, not the thread IDs within another process (TIDs of a given process have no meaning outside that process). Within the process, signals can be directed to particular TIDs. Use of <tt>raise(s)</tt> in a threaded program is equivalent to <tt>pthread_kill(pthread_self(), s)</tt>.


Signal dispositions (handlers) are per-process. Signal masks are per-thread, and inherited upon thread creation (<tt>sigprocmask()</tt> is undefined in threaded programs; <tt>pthread_sigmask()</tt> must be used). Alternate signal stacks descriptors are per-thread, and inherited upon thread creation.
Signal dispositions (handlers) are per-process. Signal masks are per-thread, and inherited upon thread creation (<tt>sigprocmask()</tt> is undefined in threaded programs; <tt>pthread_sigmask()</tt> must be used). Alternate signal stacks descriptors are per-thread, and inherited upon thread creation.
Line 45: Line 48:
* [[LinuxThreads]] on 2.2+: Same as NPTL, but three signal numbers are consumed.
* [[LinuxThreads]] on 2.2+: Same as NPTL, but three signal numbers are consumed.
* [[LinuxThreads]] before 2.0: SIGUSR1 and SIGUSR2 are used. The program must avoid use of SIGUSR1 and SIGUSR2 in either numeric or symbolic form.
* [[LinuxThreads]] before 2.0: SIGUSR1 and SIGUSR2 are used. The program must avoid use of SIGUSR1 and SIGUSR2 in either numeric or symbolic form.
 
===[[LinuxThreads]] signals===
[[LinuxThreads]] (or more accurately, <tt>clone()</tt> prior to the introduction of <tt>CLONE_PID</tt>) failed to guarantee shared PIDs among the threads of a process (each got their own). This severely compromised the POSIX signal model. No concept of process-directed signals exists in [[LinuxThreads]], so external signals are directed to one thread. A "signal manager" thread launched by the library watched for threads terminated due to signal disposition, and attempted to kill the others. Killing the signal management thread was possible, and further broke signal delivery. Signals generated by the terminal, or delivered to the process group, were sent to all threads.
==Compiling code with pthreads==
==Compiling code with pthreads==
First off, POSIX requires _REENTRANT be defined in the scope of all code run in a multithreaded manner. This is most typically achieved via -D_REENTRANT on the gcc command line. Some gcc versions / target architectures provide a -pthread option which sets -D_REENTRANT (as well as setting up pthread linking), as evidenced below:<pre>Date: Sun, 8 Apr 2007 23:33:23 -0400
First off, POSIX requires _REENTRANT be defined in the scope of all code run in a multithreaded manner. This is most typically achieved via -D_REENTRANT on the gcc command line. Some gcc versions / target architectures provide a -pthread option which sets -D_REENTRANT (as well as setting up pthread linking), as evidenced below:<pre>Date: Sun, 8 Apr 2007 23:33:23 -0400
Line 167: Line 171:
* the [[LinuxThreads]] port (devel/linuxthreads; this does NOT require emulators/linux-base*)
* the [[LinuxThreads]] port (devel/linuxthreads; this does NOT require emulators/linux-base*)
all threaded code muse use the reentrant version of the gcc builtin libs; this is done via -lgcc_r (-pthread should set this up). In addition, use -llthread to link against [[LinuxThreads]].
all threaded code muse use the reentrant version of the gcc builtin libs; this is done via -lgcc_r (-pthread should set this up). In addition, use -llthread to link against [[LinuxThreads]].
==Use with [[autotools]]==
The <tt>AX_PTHREAD</tt> [http://www.gnu.org/software/autoconf-archive/ax_pthread.html macro] from the Autoconf Archive is canonical, defining <tt>PTHREAD_LIBS</tt>, <tt>PTHREAD_CFLAGS</tt>, and <tt>PTHREAD_CC</tt>.