Mario Schwalbe wrote:
I know that Apple's non-posix extension to pthread isn't available. Nevertheless, it should be possible to at least use a bounded number of worker threads less than MAX_THREAD_COUNT (255). What about dynamically setting MAX_THREAD_COUNT (or a similar variable) to the number of processors instead?
A more useful solution would be to create a portable implementation of the Apple's pthread_workqueue interfaces [1]. This has been on my TODO list for some time, and I filed a Trac issue about this problem [2]. I don't really want to reinvent the wheel, so my first attempt will use the APR thread pool routines [3]. To prevent deadlock, each workqueue will be serviced by a separate thread pool. This won't scale to large numbers of workqueues, and makes it impossible to implement priority levels, but it should be simple and work better than creating a new thread for each task. Stacy Son has kindly documented the pthread_workqueue(3) API which should be very helpful to get the correct semantics [4]. I have taken a stab at implementing the most important functions, and it looks promising [5]. Regards, - Mark [1] datatypes: pthread_workqueue_t pthread_workqueue_attr_t functions: pthread_workqueue_init_np pthread_workqueue_attr_init_np pthread_workqueue_attr_destroy_np pthread_workqueue_attr_setqueuepriority_np pthread_workqueue_attr_setovercommit_np pthread_workqueue_create_np pthread_workqueue_additem_np [2] http://libdispatch.macosforge.org/trac/ticket/2 [3] http://apr.apache.org/docs/apr/trunk/group___a_p_r___util___t_p.html [4] http://people.freebsd.org/~sson/thrworkq/pthread_workqueue_2009_12_14.diff [5] #include <pthread.h> #include <apr-1.0/apr_thread_pool.h> #define pthread_workqueue_t apr_thread_pool_t static pthread_once_t init_once = PTHREAD_ONCE_INIT; static apr_pool_t *mpool; static int _pthread_workqueue_init(void) { return (apr_pool_create(&mpool, NULL) == APR_OK ? 0 : -1); } int pthread_workqueue_init_np(void) { pthread_once(_pthread_workqueue_init, init_once); } int pthread_workqueue_create_np( pthread_workqueue_t *workqp, const pthread_workqueue_attr_t *attr) { return (apr_thread_pool_create(workqp, 1, 255, mpool) == APR_OK ? 0 : -1); } int pthread_workqueue_additem_np( pthread_workqueue_t workq, void ( *workitem_func)(void *), void * workitem_arg, pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp) { int rv; rv = apr_thread_pool_push(workq, workitem_func, workitem_arg, APR_THREAD_TASK_PRIORITY_NORMAL, NULL); /* FIXME - Hope these aren't actually used :) */ *itemhandlep = NULL; *gencountp = 0; return (rv == APR_OK ? 0 : -1); }