[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]

General Programming Concepts: Writing and Debugging Programs

Developing Multi-Threaded Programs

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:

Compiling a Multi-Threaded Program

This section explains how to generate a multi-threaded program. It describes:

Header File

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:

_POSIX_REENTRANT_FUNCTIONS Specifies that all functions should be reentrant. Several header files use this symbol to define supplementary reentrant subroutines, such as the localtime_r subroutine.
_POSIX_THREADS Denotes the POSIX threads API. This symbol is used to check if the POSIX threads API is available. Macros or subroutines may be defined in different ways, depending on whether the POSIX or some other threads API is used.

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.

Compiler Invocation

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

Compiler Invocation for Draft 7 of POSIX 1003.1c

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.

Porting Draft 7 applications to the X/Open Version 5 Standard

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.

Memory Requirements of a Multi-Threaded Program

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

Debugging a Multi-Threaded Program

This section provides an introduction to debugging multi-threaded programs.

Using dbx

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.

Using the Kernel Debug Program

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.

Core File Requirements of a Multi-Threaded Program

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.

Related Information

Chapter 9, Parallel Programming

Thread Programming Concepts

Writing Reentrant and Thread-Safe Code

[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]