Pools of threads
Another thing that QNX OS has added is the concept of thread pools. You'll often notice in your programs that you want to run a certain number of threads but also 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 good 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 lot
of threads sitting around, waiting for further requests. In order to conserve
resources, you may decide to kill off some of those extra
threads.
- 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). When we look at thread pool functions 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 in the processing operations.
#include <sys/dispatch.h>
thread_pool_t* thread_pool_create (thread_pool_attr_t *attr, unsigned flags);
int thread_pool_destroy (thread_pool_t *pool);
int thread_pool_start (void *pool);
int thread_pool_limits (thread_pool_t *pool,
int lowater,
int hiwater,
int maximum,
int increment,
unsigned flags);
int thread_pool_control (thread_pool_t *pool,
thread_pool_attr_t *attr,
uint16_t lower,
uint16_t upper,
unsigned flags);
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 lets you modify thread pool behavior by adjusting the attributes of the
thread pool, and the
thread_pool_control()
function is a convenience wrapper for the
thread_pool_limits() function.
typedef struct _thread_pool_attr {
// thread pool functions and handle
THREAD_POOL_HANDLE_T *handle;
THREAD_POOL_PARAM_T *(*block_func)(THREAD_POOL_PARAM_T *ctp);
void (*unblock_func)(THREAD_POOL_PARAM_T *ctp);
int (*handler_func)(THREAD_POOL_PARAM_T *ctp);
THREAD_POOL_PARAM_T *(*context_alloc)(THREAD_POOL_HANDLE_T *handle);
void (*context_free)(THREAD_POOL_PARAM_T *ctp);
// thread pool parameters
pthread_attr_t *attr;
unsigned short lo_water;
unsigned short increment;
unsigned short hi_water;
unsigned short maximum;
const char *tid_name;
void (*error_func) (unsigned flags, int err_value);
} thread_pool_attr_t;
- the functions and handle for the threads in the thread pool; i.e., what the threads will do
- the operating parameters for the thread pool; i.e., when threads will be created and destroyed