A thread is an independent flow of control that operates within the same address space as other independent flows of control within a process.
One process can have multiple threads, with each thread executing different code concurrently, while sharing data and synchronizing much more easily than cooperating processes. Threads require fewer system resources than processes, and can start more quickly.
Although threads can be scheduled, they exist in the context of their process. The following list indicates what is managed at process level and shared among all threads within a process:
The process remains the swappable entity. Only a few resources are managed at thread level, as indicated in the following list:
There are three kinds of threads:
A kernel thread is a kernel entity, like processes and interrupt handlers; it is the entity handled by the system scheduler. A kernel thread runs in user mode environment when executing user functions or library calls; it switches to kernel mode environment when executing system calls.
A kernel-only thread is a kernel thread that executes only in kernel mode environment. Kernel-only threads are controlled by the kernel mode environment programmer through kernel services.
User mode programs can access user threads through a library (such as the libpthreads.a threads library). User threads are part of a portable programming model. User threads are mapped to kernel threads by the threads library, in an implementation dependent manner. The threads library uses a proprietary interface to handle kernel threads. See Understanding Threads in AIX 5L Version 5.2 General Programming Concepts: Writing and Debugging Programs to get detailed information about the user threads library and their implementation.
All threads discussed in this article are kernel threads; and the information applies only to the kernel mode environment. Kernel threads cannot be accessed from the user mode environment, except through the threads library.
The kernel maintains thread- and process-related information in two types of structures:
These structures cannot be accessed directly by kernel extensions and device drivers. They are encapsulated for portability reasons. Many fields that were previously in the user structure are now in the uthread structure.
A process is always created with one thread, called the initial thread. The initial thread provides compatibility with previous single-threaded processes. The initial thread's stack is the process stack. See Kernel Process Creation, Execution, and Termination to get more information about kernel process creation.
Other threads can be created, using a two-step procedure. The thread_create kernel service allocates and initializes a new thread, and sets its state to idle. The kthread_start kernel service then starts the thread, using the specified entry point routine.
A thread is terminated when it executes a return from its entry point, or when it calls the thread_terminate kernel service. Its resources are automatically freed. If it is the last thread in the process, the process ends.
Threads are scheduled using one of the following scheduling policies:
Scheduling parameters can be changed using the thread_setsched kernel service. The process-oriented setpri system call sets the priority of all the threads within a process. The process-oriented getpri system call gets the priority of a thread in the process. The scheduling policy and priority of an individual thread can be retrieved from the ti_policy and ti_pri fields of the thrdsinfo structure returned by the getthrds system call.
The signal handling concepts are the following:
The signal mask of a thread is handled by the limit_sigs and sigsetmask kernel services. The kthread_kill kernel service can be used to direct a signal to a particular thread.
In the kernel environment, when a signal is received, no action is taken (no termination or handler invocation), even for the SIGKILL signal. A thread in kernel environment, especially kernel-only threads, must poll for signals so that signals can be delivered. Polling ensures the proper kernel-mode serialization. For example, SIGKILL will not be delivered to a kernel-only thread that does not poll for signals. Therefore, SIGKILL is not necessarily an effective means for terminating a kernel-only thread.
Signals whose actions are applied at generation time (rather than delivery time) have the same effect regardless of whether the target is in kernel or user mode. A kernel-only thread can poll for unmasked signals that are waiting to be delivered by calling the sig_chk kernel service. This service returns the signal number of a pending signal that was not blocked or ignored. The thread then uses the signal number to determine which action should be taken. The kernel does not automatically call signal handlers for a thread in kernel mode as it does for user mode.
See Kernel Process Signal and Exception Handling for more information about signal handling at process level.