AIX supports the following standards:
The Single UNIX Specification Version 2
The specification includes the POSIX thread standard, known as the IEEE POSIX 1003.1c standard.[2] Thread implementations that conform to this standard are referred to as POSIX threads or Pthreads.[3]
[2] AIX has been supporting the IEEE POSIX 1003.1c standard since Version 4.3. Later, it was included in the Single UNIX Specification Version 2, which AIX has been supporting since Version 5.1.
[3] Currently, AIX does not support the POSIX thread option real-time extension.
The Open Group UNIX 98 specification[4]
[4] AIX has been supporting the UNIX 98 specification since Version 4.3.
The specification defines many additional functions on the former UNIX 95 specification, as well as extended threads functions over POSIX threads, based on industry input from major UNIX vendors.
On AIX, POSIX threads are defined as a set of C language programming types and sub-routine calls, implemented with a header file (/usr/include/pthread.h) and the POSIX thread library (/usr/lib/libpthreads.a).
AIX provides binary compatibility for existing multi-threaded applications that were written for the draft of Version 7 of the POSIX threads standard. The compatibility POSIX thread library,/usr/lib/libpthreads_compat.a, is only provided for backward compatibility for those applications. The compatibility POSIX thread library supports 32-bit applications only.
Both libraries are included in the bos.rte.libpthreads fileset, which is installed by default, as shown in the following example:
# lslpp -w /usr/lib/libpthreads*.a File Fileset Type --------------------------------------------------------------------------- /usr/lib/libpthreads.a bos.rte.libpthreads Symlink /usr/lib/libpthreads_compat.a bos.rte.libpthreads Symlink
The following are the advantages of using Pthreads:
The primary purpose of using Pthreads is to realize potential performance gains. POSIX threads can be created and managed with much less operating system overhead and system resources than creating and managing a process.
Inter-thread communication is more efficient and, in many cases, easier to use than inter-process communication.
Multi-threaded applications offer potential performance gains over non-threaded applications in several other ways:
- Overlapping CPUwork with I/O: For example, a program may have sections where it is performing a long I/O operation. While one Pthread is waiting for an I/O system call to complete, CPU intensive work can be performed by other Pthreads.
- Priority/Real-time scheduling: High priority jobs can be scheduled to supersede or interrupt lower priority jobs.
- Asynchronous event handling: Jobs that service events of indeterminate frequency and duration can be interleaved. For example, a Web server can both transfer data from previous requests and manage the arrival of new requests.
POSIX threads provide the infrastructure to parallelize applications using OpenMP, as explained in Chapter 9, “Program parallelization using OpenMP” on page 335.
The POSIX threads API is defined in the ANSI/IEEE POSIX 1003.1 standard. All identifiers in the Pthreads library begin with pthread_. The POSIX threads API contains over 60 subroutines. Brief descriptions about the POSIX threads sub-routines supported on AIX are provided in Appendix D, “Subroutine references for POSIX threads” on page 473.
All the POSIX threads sub-routines are categorized into several groups distinguished by the following function name prefixes:
pthread_ | Threads and miscellaneous subroutines (see Table D-1 on page 474 and Table D-6 on page 481) |
pthread_attr_ | Thread attributes objects (see Table D-2 on page 476) |
pthread_mutex_ | Managing mutexes (see Table D-3 on page 477) |
pthread_mutexattr_ | mutex attribute objects (see Table D-3 on page 477) |
pthread_cond_ | Condition variables (see Table D-3 on page 477) |
pthread_condattr_ | Condition attribute objects (see Table D-3 on page 477) |
pthread_rwlock_ | Read/Write lock objects (see Table D-5 on page 480) |
pthread_rwlockattr_ | Read/Write lock attributes (see Table D-5 on page 480) |
pthread_key_ | Thread-specific data keys (see Table D-4 on page 479) |
On AIX, the scheduling entity is a kernel thread. A single kernel thread can be mapped to multiple user threads (Pthreads) within a process (detailed information about the relationship between kernel threads and user threads is provided in 8.7.1, “Thread models in AIX” on page 322).
In order to illustrate how multi-threaded applications run on AIX, we have excerpted several lines from the ps -emo THREAD command output, as shown in Example 8-1 on page 281. The -o THREAD option instructs the ps command to display thread-level information; without this option, the command displays process-level information only.
Each column in the output represents the following:
USER | The login name of the process owner. |
PID | The process ID of the process. |
PPID | The process ID of the parent process. |
TID | The thread ID of the kernel thread. |
S | The state of the process or kernel thread. |
C | The CPU utilization of the process or kernel thread. |
PRI | The priority of the process or kernel thread. |
SC | The suspend count of the process or kernel thread. |
WCHAN | The wait channel of the process or kernel thread. |
FLAG | The flags of the process or kernel thread. |
TTY | The controlling terminal of the process. |
BND | The CPU to which the process or kernel thread is bound. |
CMD | The command being executed by the process. |
# ps -emo THREAD USER PID PPID TID ST CP PRI SC WCHAN F TT BND COMMAND root 1 0 - A 0 60 1 - 200003 - - /etc/init - - - 259 S 0 60 1 - 410410 - - - ... (some lines are omitted) ... root 10432 13686 - A 0 60 11 f015ab98 240001 - - /usr/sbin/rpc.mountd - - - 19881 S 0 60 1 f015ab98 c10400 - - - - - - 23811 Z 0 60 1 - c00001 - - - - - - 49449 Z 0 60 1 - c00001 - - - - - - 53961 Z 0 60 1 - c00001 - - - - - - 54215 Z 0 60 1 - c00001 - - - - - - 55603 S 0 60 1 - 418400 - - - - - - 60085 Z 0 60 1 - c00001 - - - - - - 60705 Z 0 60 1 - c00001 - - - - - - 62039 Z 0 60 1 - c00001 - - - - - - 63481 Z 0 60 1 - c00001 - - - - - - 63955 Z 0 60 1 - c00001 - - - ... (some lines are omitted) ... root 16266 13686 - A 0 60 1 c0042100 240001 - - /usr/sbin/qdaemon - - - 22197 S 0 60 1 c0042100 10400 - - - ... (rest of lines are omitted) ... |
In this example, the rpc.mountd daemon process (PID 10432) is a multi-threaded process, since it contains 11 lines underneath the highlighted line, while the qdaemon daemon process (PID 16266) is a single-threaded process, since it has only one line that represents the kernel thread for the process’s initial thread.
Two kernel threads (TID 19881 and 55603) of PID 10432 shown the status S, which means the kernel thread is in the sleeping status. Other kernel threads did not exist at the time the ps command was invoked, though TIDs were displayed.
the process could be verified by inspecting the /proc file system.[5] The /proc file system is a system interface to represent process information. The process information for the process <PID> is shown as several files and sub-directories under the /proc/<PID> directory.
[5] AIX has been supporting the /proc file system since AIX 5L Version 5.1.
As shown in Example 8-2 on page 282, there were only two sub-directories, 19881 and 55603, under the /proc/10432/Iwp directory[6] at the moment the ps command was invoked. The sub-directory names, 19881 and 55603, were the same TIDs for the PID 10432 in Example 8-1.
[6] LWP stands for light-weight process. In the /proc file system semantic, kernel threads are represented as LWPs.
# ls /proc/10432 as ctl fd/ map psinfo status cred cwd@ lwp/ object/ sigact sysent # ls /proc/10432/lwp 19881/ 55603/ # ls -lR /proc/10432/lwp total 0 dr-xr-xr-x 1 root system 0 Feb 21 18:41 19881/ dr-xr-xr-x 1 root system 0 Feb 21 18:41 55603/ /proc/10432/lwp/19881: total 0 --w------- 1 root system 0 Feb 21 18:41 lwpctl -r--r--r-- 1 root system 120 Feb 21 18:41 lwpsinfo -r-------- 1 root system 1200 Feb 21 18:41 lwpstatus /proc/10432/lwp/55603: total 0 --w------- 1 root system 0 Feb 21 18:41 lwpctl -r--r--r-- 1 root system 120 Feb 21 18:41 lwpsinfo -r-------- 1 root system 1200 Feb 21 18:41 lwpstatus |
For further information about the /proc file system, please refer to the AIX 5L Version 5.2 Files Reference.
Although the rpc.mountd daemon process (PID 10432) was easily determined to be a multi-threaded process in Example 8-1 on page 281, in order to determine if the qdaemon daemon process (PID 16266) is non-threaded, use the ldd[7] command against the executable file, as shown in Example 8-3. Because qdaemon does not depend on the POSIX thread library, we are sure that it is not a multi-threaded program.
[7] The ldd command is supported on AIX 5L Version 5.2 and later. On earlier versions of AIX, use the dump -H command.
# ldd /user/sbin/qdaemon /usr/sbin/qdaemon needs: /usr/lib/libc.a(shr.o) /usr/lib/libqb.a(shr.o) /unix /usr/lib/libcrypt.a(shr.o) |
When a process is created, one user thread is automatically created. This user thread is called the initial thread. It ensures the compatibility between the non-threaded processes with a unique implicit Pthread and the multi-threaded processes. The initial thread has some special properties, not visible to the programmer, that ensure binary compatibility between the non-threaded processes and the multi-threaded operating system. It is also the initial thread that executes the main function in multi-threaded programs.
In the multi-process UNIX programming semantic, a system call or sub-routine would set a non-zero value to the global variable errno in case of failure. This is still true in multi-threaded programming, though there is a subtle difference.
Within a multi-threaded process, each Pthread has its own errno to avoid being overwritten by the other Pthreads. On AIX, the Pthread-basis errno is implemented as a macro to a function pointer to an internal function, as shown in Example 8-4, which is excerpted from /usr/include/errno.h.[8] In the multi-threaded programming on AIX, the_THREAD_SAFE macro is always defined.
[8] In the POSIX thread standard, the Pthread-basis errno is defined as implementation-dependent.
#if defined(_THREAD_SAFE) || defined(_THREAD_SAFE_ERRNO)
/*
* Per thread errno is provided by the threads provider. Both the extern int
* and the per thread value must be maintained by the threads library.
*/
extern int *_Errno( void );
#define errno (*_Errno())
#else
extern int errno;
#endif /* _THREAD_SAFE || _THREAD_SAFE_ERRNO */
|
Although the process level global symbol errno is still accessible from Pthreads within a process, references to it is unreliable and useless in the multi-threaded programming.
Therefore, all the multi-threaded applications that reference to errno must have the following directive:
#include <errno.h>
and must not have the following declaration:
extern int errno;
Note
Avoid directly referencing the internal function, because this is implementation-dependent and may be subject to change in future versions of AIX. Use the errno macro to assure the portability of your multi-threaded applications.