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):

// 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);
Note: In order to correctly define THREAD_POOL_PARAM_T, #include <sys/resmgr.h> before <sys/dispatch.h>.

Recall from the diagram “Thread flow when using thread pools,” that the context_alloc() function gets called for every new thread being created. (Similarly, the context_free() function gets called for every thread being destroyed.)

The handle member of the structure (above) is passed to the context_alloc() function as its sole parameter. The context_alloc() function is responsible for performing any per-thread setup required and for returning a context pointer (called ctp in the parameter lists). Note that the contents of the context pointer are entirely up to you—the library doesn't care what you put into the context pointer.

Now that the context has been created by context_alloc(), the block_func() function is called to perform the blocking operation. Note that the block_func() function gets passed the results of the context_alloc() function. Once the block_func() function unblocks, it returns a context pointer, which gets passed by the library to the handler_func(). The handler_func() is responsible for performing the “work”—for example, in a typical server, this is where the message from the client is processed. The handler_func() must return a zero for now—nonzero values are reserved for future expansion by QNX Software Systems. The unblock_func() is also reserved at this time; just leave it as NULL. Perhaps this pseudo code sample will clear things up (it's based on the same flow as shown in “Thread flow when using thread pools,” above):

FOREVER DO
    retval = (*block_func) (context);
    IF (#threads < lo_water) THEN
        IF (#threads_total < maximum) THEN
            create new thread
            context = (*context_alloc) (handle);
        ENDIF
    ENDIF

    (*handler_func) (retval);
    IF (#threads > hi_water) THEN
       (*context_free) (context)
       kill thread
    ENDIF
DONE

Note that the above is greatly simplified; its only purpose is to show you the data flow of the ctp and handle parameters and to give some sense of the algorithms used to control the number of threads.