Developing multi-threaded programs is not much more complicated than developing programs with multiple processes. See Chapter 11, Threads Programming Guidelines for detailed information about using the threads library. Developing programs also implies compiling and debugging the code.
Read the following to learn more about developing multi-threaded programs:
This section explains how to generate a multi-threaded program. It describes:
All subroutine prototypes, macros, and other definitions for using the threads library are in one header file, pthread.h, located in the /usr/include directory.
The pthread.h
header file must be the first included file of each source file using the
threads library, because it defines some important macros that affect other
header files. Having the pthread.h header file as the
first included file ensures the usage of thread-safe subroutines. The
following global symbols are defined in the pthread.h
file:
The pthread.h file also redefines the errno global variable as a function returning a thread-specific errno value. The errno identifier is, therefore, no longer an l-value in a multi-threaded program.
When compiling a multi-threaded
program, you should invoke the C compiler using one of the following
commands:
xlc_r | Invokes the compiler with default language level of ansi. |
cc_r | Invokes the compiler with default language level of extended. |
These commands ensure that the adequate options and libraries are used to be compliant with the X/Open Version 5 Standard. The POSIX Threads Specification 1003.1c is a subset of the X/Open Specification.
The following libraries are automatically linked with your program when
using these commands:
libpthreads.a | Threads library. |
libc.a | Standard C library |
For example, the following command compiles the foo.c multi-threaded C source file and produces the foo executable file:
cc_r -o foo foo.c
AIX provides source code compatibility for Draft 7 applications. It is recommended that developers port their threaded application to the latest standard, which is covered by the compiler directions provided above.
When compiling a multi-threaded program for Draft 7 support of threads, you
should invoke the C compiler using one of the following commands:
xlc_r7 | Invokes the compiler with default language level of ansi. |
cc_r7 | Invokes the compiler with default language level of extended. |
The following libraries are automatically linked with your program when
using these commands:
libpthreads_compat.a | Draft 7 Compatibility Threads library. |
libpthreads.a | Threads library. |
libc.a | Standard C library. |
Source code compatibility has been achieved through the use of the compiler directive _AIX_PTHREADS_D7. It is also necessary to link the libraries in the following order: libpthreads_compat.a, libpthreads.a, and libc.a. Most users do not need to know this information, since the commands listed above provide the necessary options. These options are provided for those that don't have the latest AIX compiler.
There are very few differences between Draft 7 and the final standard.
There are some minor errno differences. The most prevalent is the use of ESRCH to denote the specified pthread could not be found. Draft 7 frequently returned EINVAL for this failure.
Pthreads are joinable by default. This is a significant change since it can result in a memory leak if ignored. See Creating Threads for more information about thread creation.
Pthreads have process scheduling scope by default. See Threads Scheduling for more information about scheduling.
The subroutine pthread_yield has been replaced by sched_yield.
The various scheduling policies associated with the mutex locks are slightly different.
AIX supports up to 32768 threads in a single process. Each individual pthread requires some amount of process address space so the actual maximum number of pthreads a process can have depends on the memory model and the use of process address space for other purposes. The amount of memory a pthread needs includes the stack size and the guard region size plus some amount for internal use. The user can control the size of the stack with pthread_attr_setstacksize() and the size of the guard region with pthread_attr_setguardsize(). The following table points out the maximum number of pthreads which could be created in a 32-bit process using a simple program which does nothing other than create pthreads in a loop using the NULL pthread attribute. In a real program the actual numbers will depend on other memory usage in the program. For a 64-bit process the ulimit controls how many threads can be created therefore the big data model is not necessary and in fact can decrease the maximum number of threads.
32-bit Process:
Data Model | -bmaxdata: | Maximum Pthreads |
---|---|---|
Small Data | n/a | 1084 |
Big Data | 0x10000000 | 2169 |
Big Data | 0x20000000 | 4340 |
Big Data | 0x30000000 | 6510 |
Big Data | 0x40000000 | 8681 |
Big Data | 0x50000000 | 10852 |
Big Data | 0x60000000 | 13022 |
Big Data | 0x70000000 | 15193 |
Big Data | 0x80000000 | 17364 |
This section provides an introduction to debugging multi-threaded programs.
Application programmers can use the dbx program to perform debugging. Several new subcommands are available for displaying thread-related objects: attribute, condition, mutex, and thread.
Kernel programmers can use the kernel debug program to perform debugging on kernel extensions and device drivers. The kernel debug program provides no access to user threads but handles kernel threads.
Several new commands have been added to support multiple kernel threads and processors: cpu, ppd, thread, and uthread. These commands respectively change the current processor, display per-processor data structures, display thread table entries, and display the uthread structure of a thread.
By default processes do not generate a full core file. Before AIX 4.3 this meant only the stack for the thread causing the core dump was written to the core file. Before AIX 4.3.2 this meant the part of the process address space made up of shared memory region was not written to the core file. If an application needs to debug data in shared memory regions, particular thread stacks it will be necessary to generate a full core dump. To generate full core file information the following command must be run as root:
chdev -l sys0 -a fullcore=true
Each individual pthread adds to the size of the generated core file. The amount of core file space a pthread needs includes the stack size which the user can control with pthread_attr_setstacksize(). For pthreads created with the NULL pthread attribute each pthread in a 32-bit process adds 128KB to the size of the core file and each pthread in a 64-bit process ads 256KB to the size of the core file.
Chapter 9, Parallel Programming
Writing Reentrant and Thread-Safe Code