Pools of threads

Another thing that QNX Neutrino has added is the concept of thread pools.
You'll often notice in your programs that you want to be able
to run a certain number of threads, but you also want to be able to control
the behavior of those threads within certain limits.
For example, in a server you may decide that initially just one thread should
be blocked, waiting for a message from a client.
When that thread gets a message and is off servicing a request, you may decide that it would be a
good idea to create another thread, so that it could be blocked waiting in
case another request arrived.
This second thread would then be available to handle that request.
And so on.
After a while, when the requests had been serviced, you would now have a large number
of threads sitting around, waiting for further requests. In order to conserve
resources, you may decide to kill off some of those "extra" threads.

This is in fact a common operation, and QNX Neutrino provides a library to help
with this.
We'll see the thread pool functions again in the
Resource Managers
chapter.

It's important for the discussions that follow to realize there are really two distinct
operations that threads (that are used in thread pools) perform:

a blocking (waiting operation)

a processing operation

The blocking operation doesn't generally consume CPU.
In a typical server, this is where the thread is waiting for a message to arrive.
Contrast that with the processing operation, where the thread may or may not be consuming
CPU (depending on how the process is structured).
In the thread pool functions that we'll look at later, you'll see that we have the ability
to control the number of threads in the blocking operation as well as the
number of threads that are in the processing operations.

QNX Neutrino provides the following functions to deal with thread pools:

As you can see from the functions provided, you first create a thread pool definition
using
thread_pool_create(),
and then start the thread pool via
thread_pool_start().
When you're done with the thread pool, you can use
thread_pool_destroy()
to clean up after yourself.
Note that you might never call thread_pool_destroy(), as in the case where the
program is a server that runs "forever."
The
thread_pool_limits()
function is used to specify thread pool behavior and adjust attributes of the thread pool,
and the
thread_pool_control()
function is a convenience wrapper for the
thread_pool_limits()
function.

So, the first function to look at is thread_pool_create().
It takes two parameters, attr and flags.
The attr is an attributes structure that defines the operating characteristics
of the thread pool (from <sys/dispatch.h>):

I've broken the thread_pool_attr_t type into two sections, one that
contains the functions and handle for the threads in the thread pool, and another
that contains the operating parameters for the thread pool.

Controlling the number of threads
Let's first look at the "thread pool parameters" to see how you control the number and attributes of threads that will be operating in this thread pool. Keep in mind that we'll be talking about the "blocking operation" and the "processing operation" (when we look at the callout functions, we'll see how these relate to each other).

The thread pool functions
Now that we have a good feel for how the number of threads is controlled, let's turn our attention to the other members of the thread pool attribute structure (from above):