Compiling a Multithreaded Application
This is a mirror of
the Notes from Dave Marshall's excellent notes on
There are many options to consider for header files, define flags, and linking.
Preparing for Compilation
The following items are required to compile and link a multithreaded program.
* A standard C compiler (cc, gcc etc)
* Include files:
o , , ,
* The Solaris threads library (libthread), the POSIX threads library (libpthread), and possibly the POSIX realtime library (libposix4) for semaphores
* MT-safe libraries (libc, libm, libw, libintl, libnsl, libsocket, libmalloc, libmapmalloc, and so on)
The include file , used with the -lthread library, compiles code that is upward compatible with earlier releases of the Solaris system. This library contains both interfaces: those with Solaris semantics and those with POSIX semantics. To call thr_setconcurrency() with POSIX threads, your program needs to include .
The include file , used with the -lpthread library, compiles code that is conformant with the multithreading interfaces defined by the POSIX 1003.1c standard. For complete POSIX compliance, the define flag _POSIX_C_SOURCE should be set to a (long) value $\geq 199506$, as follows:
cc [flags] file... -D_POSIX_C_SOURCE=N (where N 199506L)
You can mix Solaris threads and POSIX threads in the same application, by including both and , and linking with either the -lthread or -lpthread library. In mixed use, Solaris semantics prevail when compiling with -D_REENTRANT flag set $\geq 199506L$ and linking with -lthread, whereas POSIX semantics prevail when compiling with D_POSIX_C_SOURCE flag set $\geq 199506L$ and linking with -lpthread. Defining _REENTRANT or _POSIX_C_SOURCE
Linking With libthread or libpthread
For POSIX threads behavior, load the libpthread library. For Solaris threads behavior, load the libthread library. Some POSIX programmers might want to link with -lthreadto preserve the Solaris distinction between fork() and fork1(). All that -lpthread really does is to make fork() behave the same way as the Solaris fork1() call, and change the behavior of alarm().
To use libthread, specify -lthread last on the cc command line.
To use libpthread, specify -lpthread last on the cc command line.
Do not link a nonthreaded program with -lthread or -lpthread. Doing so establishes multithreading mechanisms at link time that are initiated at run time. These slow down a single-threaded application, waste system resources, and produce misleading results when you debug your code.
Note: For C++ programs that use threads, use the -mt option, rather than -lthread, to compile and link your application. The -mt option links with libthread and ensures proper library linking order. ( Using -lthread might cause your program to crash (core dump).
Linking with -lposix4 for POSIX Semaphores
The Solaris semaphore routines (see Chapter 30.3) are contained in the libthread library. By contrast, you link with the -lposix4 library to get the standard POSIX semaphore routines (See Chapter 25)
Debugging a Multithreaded Program
The following list points out some of the more frequent oversights and errors that can cause bugs in multithreaded programs.
* Passing a pointer to the caller's stack as an argument to a new thread.
* Accessing global memory (shared changeable state) without the protection of a synchronization mechanism.
* Creating deadlocks caused by two threads trying to acquire rights to the same pair of global resources in alternate order (so that one thread controls the first resource and the other controls the second resource and neither can proceed until the other gives up).
* Trying to reacquire a lock already held (recursive deadlock).
* Creating a hidden gap in synchronization protection. This is caused when a code segment protected by a synchronization mechanism contains a call to a function that frees and then reacquires the synchronization mechanism before it returns to the caller. The result is that it appears to the caller that the global data has been protected when it actually has not.
* Mixing UNIX signals with threads -- it is better to use the sigwait() model for handling asynchronous signals.
* Forgetting that default threads are created PTHREAD_CREATE_JOINABLE and must be reclaimed with pthread_join(). Note, pthread_exit() does not free up its storage space.
* Making deeply nested, recursive calls and using large automatic arrays can cause problems because multithreaded programs have a more limited stack size than single-threaded programs.
* Specifying an inadequate stack size, or using non-default stacks. And, note that multithreaded programs (especially those containing bugs) often behave differently in two successive runs, given identical inputs, because of differences in the thread scheduling order.
In general, multithreading bugs are statistical instead of deterministic. Tracing is usually a more effective method of finding order of execution problems than is breakpoint-based debugging.