William A. Rowe, Jr. wrote:
Henry Jen wrote:
Hi,
We would like to implement thread pool capability, and think it might
be a good addition to apr-util or apr.
Interesting!
I don't see where your thread join occurs to reap any terminated threads,
that is, how your model handles threads that have decided they are 'done'.
The thread remains in the pool until the thread_pool tells the thread to
stop and that's where join will happen.
One place is apr_thread_pool_stop_unused_threads.
APR_DECLARE(int) apr_thread_pool_get_num_unused_threads(void);
AIUI the style apr_thread_pool_unused_threads_num_get() would be
appropriate
(_num seems awkward though, I personally prefer _count, or nothing).
I am OK with the naming convention as long as there is one. :-)
/**
* Stop all unused threads. Ignore the maximum number of idling threads.
* @return The total number of threads stopped.
*/
APR_DECLARE(int) apr_thread_pool_stop_unused_threads(void);
I'm a little confused in your proposal between apr_thread_pool_terminate(),
apr_thread_pool_destroy(), and this function.
Can't this be reduced to
My mistake. The last couple functions should take a apr_thread_pool_t
*self as a parameter. Those are instance methods, not static.
This may address all the following questions.
Attached please find updated version.
Cheers,
Henry
apr_thread_pool_shutdown() (blocks)
apr_thread_pool_destroy() (same as pool cleanup)
Can you elaborate?
Final observation, your model seemed a little shortsighted, in that it
permits
only a single thread pool. This is great for an app, lousy for another
library
which wishes to build upon the model. And a group of threads might be
shut down
independently of a second pool.
Can you refine the proposal with an apr_threadpool_t * object which
prevents
us from adding yet another evil static singleton? Or as an alternative,
bind
the threadpool as an attribute of the pool itself, identifying the
thread pool
by apr_pool_t *?
Bill
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
* applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef APR_THREAD_POOL_H
#define APR_THREAD_POOL_H
/**
* @file apr_thread_pool.h
* @brief APR Thread Pool Library
* @remarks This library implements a thread pool using apr_thread_t. A thread
* pool is a set of threads that can be created in advance or on demand until a
* maximum number. When a task is scheduled, the thread pool will find an idle
* thread to handle the task. In case all existing threads are busy, the pool
* will try to create a new thread to serve the task if the maximum number has
* not been reached. Otherwise, the task will be put into a queue based on
* priority, which can be valued from 0 to 255, with higher value been served
* first. In case there are tasks with the same priority, the new task is put at
* the top or the bottom depeneds on which function is used to put the task.
*
* @remarks There may be the case that a thread pool can use up the maximum
* number of threads at peak load, but having those threads idle afterwards. A
* maximum number of idle threads can be set so that extra idling threads will
* be terminated to save system resrouces.
*/
#ifdef __cplusplus
extern "C" {
#if 0
};
#endif
#endif /* __cplusplus */
/** Opaque Thread Pool structure. */
typedef struct _apr_thread_pool apr_thread_pool_t;
/**
* The prototype for any APR thread pool task functions.
* @param apr_thread_t the apr_thread_t structure for the thread is executing the task
* @param void * a pointer to the user data passed in when schedule the task
*/
typedef void* (APR_THREAD_FUNC *apr_thread_pool_task_t) (apr_thread_t *, void *)
#define APR_THREAD_TASK_PRIORITY_LOWEST 0
#define APR_THREAD_TASK_PRIORITY_LOW 63
#define APR_THREAD_TASK_PRIORITY_NORMAL 127
#define APR_THREAD_TASK_PRIORITY_HIGH 191
#define APR_THREAD_TASK_PRIORITY_HIGHEST 255
/**
* Setup all of the internal structures required to use thread pools
*/
APR_DECLARE(apr_status_t) apr_thread_pool_init(void);
/**
* Tear down all of the internal structures required to use pools
*/
APR_DECLARE(void) apr_thread_pool_terminate(void);
/**
* Create a thread pool
* @param pool The pool to use
* @param init_threads The number of threads to be created initially, the number
* will also be used as the initial value for maximum number of idle threads.
* @param max_threads The maximum number of threads that can be created
* @param err Receive the error code, can be NULL if not needed.
* @return The thread pool. NULL if failed to create the thread pool. Put the
* error code in the err parameter if it is not NULL.
*/
APR_DECLARE(apr_thread_pool_t*) apr_thread_pool_create(apr_pool_t *pool,
int init_threads,
int max_threads,
apr_status_t *err);
/**
* Destroy the thread pool and stop all the threads
* @return APR_SUCCESS if all threads are stopped.
*/
APR_DECLARE(apr_status_t) apr_thread_pool_destroy(apr_thread_pool_t *self);
/**
* Schedule a task to the bottom of the tasks of same priority.
* @param self The thread pool
* @param task The task function
* @param param The parameter for the task function
* @param priority The priority of the task.
* @return APR_SUCCESS if the task had been scheduled successfully
*/
APR_DECLARE(apr_status_t) apr_thread_pool_push(apr_thread_pool_t *self,
apr_thread_pool_task_t *task,
void *param,
apr_byte_t priority);
/**
* Schedule a task to the top of the tasks of same priority.
* @param self The thread pool
* @param task The task function
* @param param The parameter for the task function
* @param priority The priority of the task.
* @return APR_SUCCESS if the task had been scheduled successfully
*/
APR_DECLARE(apr_status_t) apr_thread_pool_top(apr_thread_pool_t *self,
apr_thread_pool_task_t *task,
void *param,
apr_byte_t priority);
/**
* Get current number of tasks waiting in the queue
* @param self The thread pool
* @return Number of tasks in the queue
*/
APR_DECLARE(int) apr_thread_pool_tasks_cnt_get(apr_thread_pool_t *self);
/**
* Access function for the maximum number of idling thread
* @param self The thread pool
* @param cnt The number
*/
APR_DECLARE(void) apr_thread_pool_unused_max_set(apr_thread_pool_t *self,
int cnt);
/**
* Access function for the maximum number of idling thread
* @param self The thread pool
* @return The current maximum number
*/
APR_DECLARE(int) apr_thread_pool_unused_max_get(apr_thread_pool_t *self);
/**
* Get current number of idling thread
* @param self The thread pool
* @return Number of idling threads
*/
APR_DECLARE(int) apr_thread_pool_unused_cnt_get(apr_thread_pool_t *self);
/**
* Stop all unused threads. Ignore the maximum number of idling threads.
* @param self The thread pool
* @return The total number of threads stopped.
*/
APR_DECLARE(int) apr_thread_pool_stop_unused_threads(apr_thread_pool_t *self);
#ifdef __cplusplus
#if 0
{
#endif
}
#endif
#endif /* APR_THREADPOOL_H */