Create a thread pool handle
#include <sys/iofunc.h> #include <sys/dispatch.h> thread_pool_t * thread_pool_create ( thread_pool_attr_t * pool_attr, unsigned flags );
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
The thread_pool_create() function creates a thread pool handle. This handle is then used to start a thread pool with thread_pool_start(). With the thread pool functions, you can create and manage a pool of worker threads.
The worker threads work in the following way:
The thread continues to block and handle events until the thread pool decides this worker thread is no longer needed. Finally, when the worker thread exits, it releases the allocated context.
The thread pool manages these worker threads so that there's a certain number of them in the blocked state. Thus, as threads become busy in the handler function, the thread pool creates new threads to keep a minimum number of threads in a state where they can accept requests from clients. By the same token, if the demand on the thread pool goes down, the thread pool lets some of these blocked threads exit.
The pool_attr argument sets the:
The thread_pool_attr_t structure that the pool_attr argument points to is defined in <sys/dispatch.h> as:
typedef struct _thread_pool_attr { 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); pthread_attr_t *attr; unsigned short lo_water; unsigned short increment; unsigned short hi_water; unsigned short maximum; unsigned reserved[8]; } thread_pool_attr_t;
The members include:
A thread pool handle, or NULL if an error occurs (errno is set).
Here's a simple multithreaded resource manager:
/* Define an appropriate interrupt number: */ #define INTNUM 0 #include <stdio.h> #include <stddef.h> #include <stdlib.h> #include <sys/iofunc.h> #include <sys/dispatch.h> #include <sys/neutrino.h> static resmgr_connect_funcs_t connect_funcs; static resmgr_io_funcs_t io_funcs; static iofunc_attr_t attr; void *interrupt_thread( void *data) /* *data isn't used */ { struct sigevent event; int id; /* fill in "event" structure */ memset( &event, 0, sizeof(event) ); event.sigev_notify = SIGEV_INTR; /* INTNUM is the desired interrupt level */ id = InterruptAttachEvent( INTNUM, &event, 0 ); … while (1) { InterruptWait( 0, NULL ); /* do something about the interrupt, perhaps updating some shared structures in the resource manager unmask the interrupt when done */ InterruptUnmask( INTNUM, id ); } } int main(int argc, char **argv) { thread_pool_attr_t pool_attr; thread_pool_t *tpp; dispatch_t *dpp; resmgr_attr_t resmgr_attr; int id; if((dpp = dispatch_create()) == NULL) { fprintf( stderr, "%s: Unable to allocate dispatch handle.\n", argv[0] ); return EXIT_FAILURE; } memset( &pool_attr, 0, sizeof pool_attr ); pool_attr.handle = dpp; pool_attr.context_alloc = dispatch_context_alloc; pool_attr.block_func = dispatch_block; pool_attr.unblock_func = dispatch_unblock; pool_attr.handler_func = dispatch_handler; pool_attr.context_free = dispatch_context_free; pool_attr.lo_water = 2; pool_attr.hi_water = 4; pool_attr.increment = 1; pool_attr.maximum = 50; if((tpp = thread_pool_create( &pool_attr, POOL_FLAG_EXIT_SELF)) == NULL ) { fprintf(stderr, "%s: Unable to initialize thread pool.\n", argv[0]); return EXIT_FAILURE; } iofunc_func_init( _RESMGR_CONNECT_NFUNCS, &connect_funcs, _RESMGR_IO_NFUNCS, &io_funcs ); iofunc_attr_init( &attr, S_IFNAM | 0666, 0, 0 ); memset( &resmgr_attr, 0, sizeof resmgr_attr ); resmgr_attr.nparts_max = 1; resmgr_attr.msg_max_size = 2048; if((id = resmgr_attach( dpp, &resmgr_attr, "/dev/mynull", _FTYPE_ANY, 0, &connect_funcs, &io_funcs, &attr )) == -1) { fprintf( stderr, "%s: Unable to attach name.\n", argv[0] ); return EXIT_FAILURE; } /* Start the thread which will handle interrupt events. */ pthread_create ( NULL, NULL, interrupt_thread, NULL ); /* Never returns */ thread_pool_start( tpp ); }
For more examples using the dispatch interface, see dispatch_create(), message_attach(), and resmgr_attach(). For information on advanced topics in designing and implementing a resource manager, see the Combine Messages chapter of Writing a Resource Manager.
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | No |
Signal handler | No |
Thread | Yes |
dispatch_block(), dispatch_create(), dispatch_unblock(), pthread_create(), resmgr_attach(), select_attach(), thread_pool_destroy(), thread_pool_start()
Processes and Threads chapter of Getting Started with QNX Neutrino