I. Overview
In today's era of multi-core development, programmers are required to write high-concurrency programs, while multiple cores are typically used in two ways: multithreaded or multi-process. If a thread or process is temporarily generated when a new task is processed and the threads or processes exit immediately after the task is processed, it is very inefficient to show that this is the case, so people generally adopt a thread pool model (which is very common in Java or. NET) or a multi-process process pool model (which is typically used on UNIX platforms). In addition, there are two scenarios for the thread pool or process pool model: Often resident memory or semi-resident memory, which refers to pre-generating a batch of threads or processes, waiting for new tasks to arrive, and those threads or processes are resident memory even in idle state Semi-resident memory refers to when a new task is coming, if the thread pool or process pool does not have the available threads or processes to start a new thread or process to handle the new task, the thread or process does not immediately exit, but the specified time is idle, and the new task is processed immediately if a new task arrives before the idle threshold time arrives, such as If no new tasks arrive after the idle timeout is reached, these idle threads or processes exit to yield system resources. Therefore, compared with the resident memory mode and semi-resident memory mode, it is not difficult to see that the semi-resident mode is more on demand.
The following is an example of how to write a semi-resident thread pool program using the semi-resident thread pool model in the ACL framework.
Second, semi-resident thread pool function Interface description
2.1) interface of thread pool creation, destruction and task addition
/** * creates a thread pool object * @param attr {acl_pthread_pool_attr_t*} property when the thread pool is created, if the parameter is empty, * uses the default parameter: acl_pthread_pool_def_xxx * @return {acl_pthread_pool_t*}, If not empty indicates success, otherwise failure */acl_api acl_pthread_pool_t *acl_pthread_pool_create (Const acl_pthread_ POOL_ATTR_T *ATTR);/** * destroys a thread pool object, The object cannot be used again after the successful destruction of . * @param thr_pool { acl_pthread_pool_t*} thread Pool object, cannot be empty * @return {int} 0: successful; != 0: failed */acl_api int acl_pthread_pool_destroy (Acl_pthread_pool_t *thr_pool);/** * Add a task * @param thr_pool {acl_pthread_pool_t*} thread pool object to the thread pool, cannot be empty * @param run_fn {void (*) (*)} callback handler that is called when there are available worker threads * @param run_arg {void*} Callback function run_fn required callback parameters * @return {int} 0: successful; != 0: failure */acl_api int acl_pThread_pool_add (acl_pthread_pool_t *thr_pool, void (* RUN_FN) (void *), void *run_arg);/** * the number of threads in the current thread pool * @param thr_pool {acl_pthread_pool_t*} thread Pool object, cannot be empty * @return {int} returns the number of bus threads in the thread pool */acl_api int acl_pthread_pool_size (Acl_pthread_pool_t *thr_pool);
2.2) Thread pool property settings interface
/** * Initialize thread pool property values * @param attr {acl_pthread_pool_attr_t*} */ACL_API Void acl_pthread_pool_attr_init (acl_pthread_pool_attr_t *attr);/** * setting the maximum stack size in a thread pool property (bytes) * @param attr {acl_pthread_pool_attr_t*} * @param size {size_t} */acl_api void acl_pthread_pool_attr_set_stacksize (acl_pthread_pool_attr_t *attr, size_t size);/** * Set the maximum number of threads in the thread pool property limit value * @param attr {acl_pthread_pool_attr_t*} * @param threads_limit {int} Maximum number of threads in the thread pool */acl_api void acl_pthread_ Pool_attr_set_threads_limit (acl_pthread_pool_attr_t *attr, int threads_limit);/** * set thread pool properties threads Idle Timeout value * @param attr {acl_pthread_pool_attr_t*} * @param idle_timeout {int} thread idle timeout time (sec) */acl_api void acl_pthread_pool_attr_set_idle_timeout (acl_pthread_pool_attr_t *attr, &nBsp; int idle_timeout);
2.3) Set callback function interface when worker threads in thread pool are created and exited
/** * Add registration function, execute this initialization function immediately after thread creation * @param thr_pool {acl_pthread_pool_t*} thread Pool Object , cannot be empty * @param init_fn {int (*) (void*)} worker thread initialization function, If the function returns < 0 , * the thread exits automatically. * @param init_arg {void*} init_fn Required Parameters * @return {int} 0: ok; != 0: error. */acl_api int acl_pthread_pool_atinit (acl_pthread_pool_t *thr_pool, int (*INIT_FN) (void *), void &NBSP;*INIT_ARG);/** * Add the registration function, the thread exits the immediate execution of this initial function * @param thr_pool {acl_pthread_pool_ t*} thread Pool object, cannot be empty * @param free_fn {void (*) (void*)} a function that must be executed before the worker thread exits * @param free_arg {void*} free_fn Required Parameters * @return {int} 0: Ok; != 0: error. */acl_api int acl_pthread_pool_atfree (Acl_pthread_pool_t *thr_pool, void (*FREE_FN) (void *), VOID&NBSP;*FREE_ARG);
Third, semi-resident thread pool example
3.1) Program code
#include "lib_acl.h" #include <assert.h>/** * user-defined data structure */typedef struct thread_ctx {acl_pthread_pool_t *thr_pool;int i;} THREAD_CTX;/* global static variable */static acl_pthread_pool_t *__thr_pool = null;/* Thread-Local storage variables (C99 supports this way of declaring for many convenience) */static __thread unsigned int __local = 0 ; Static void work_thread_fn (Void *arg) {thread_ctx *ctx = (THREAD_CTX*) arg; /* get user-defined objects */int i = 5;/* Validation parameter pass-through process */assert (ctx-> Thr_pool == __thr_pool);while (i-- > 0) {printf ("thread start! tid= %d, i=%d, __local=%d\r\n ", Acl_pthread_self (), ctx->i, __local);/* thread local variable plus 1 in this thread */__local++;sleep (1);} Acl_myfree (CTX);/* at this point, the worker thread enters an idle state until the idle timeout exits */}static int on_thread_init (void *arg) { const char *myname = "On_thread_init";acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg;/* , just to verify that the parameter passing process */assert (Thr_pool == __thr_pool);p rintf ("%s: thread (%d) init now\r\n ", myname, acl_pthread_self ());/* returns 0 to continue executing the new task that the thread obtains, and returns 1 to stop the task from executing */return (0);} Static void on_thread_exit (Void *arg) {const char *myname = "On_thread_exit" ;acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg;/* just to verify the parameter passing process * /assert (Thr_pool == __thr_pool);p rintf ("%s: thread (%d) exit now\r\n", myname, acl_pthread_self ());} Static void run_thread_pool (acl_pthread_pool_t *thr_pool) {thread_ctx *ctx; /* user-defined parameters *//* setting global static variables */__thr_pool = thr_pool;/* setting the callback function at the start of a thread */(void ) acl_pthread_pool_atinit (Thr_pool, on_thread_init, thr_pool);/* Sets the callback function */(void) acl_pthread_pool_atfree (thr_pool, on_thread_exit, thr_pool) when the thread exits; ctx = (thread_ctx*) acl_mycalloc (1, sizeof (THREAD_CTX)); assert (CTX); ctx->thr_pool = thr_pool;ctx->i = 0;/** * Add the first task to the thread pool, which starts the first worker thread * @param thr_ pool thread pool handles * @param workq_thread_fn callback functions for worker threads * @param ctx user-defined parameters */acl_pthread_pool_add (THR_POOL,&NBSP;WORK_THREAD_FN,&NBSP;CTX); sleep (1);ctx = (THREAD_CTX*) acl_mycalloc (1, sizeof (THREAD_CTX)); assert (CTX); ctx->thr_pool = thr_pool;ctx->i = 1;/* Add a second task to the thread pool, which starts the second worker thread */acl_pthread_pool_add (THR_POOL,&NBSP;WORK_THREAD_FN, &NBSP;CTX);} Int main (int argc acl_unused, char *argv[] acl_unused) {acl_pthread_pool_t * thr_pool;int max_threads = 20; /* up to 20 concurrent threads */int idle_ Timeout = 10; /* automatically exits after each worker thread is idle for 10 seconds */acl_pthread_pool_attr_t attr;acl_pthread_pool_attr_init (&attr ); Acl_pthread_pool_attr_set_threads_limit (&attr, max_threads); Acl_pthread_pool_attr_set_idle_timeout ( &attr, idle_timeout);/* Create semi-resident thread handle */thr_pool = acl_pthread_pool_create (&ATTR) ; assert (Thr_pool); Run_thread_pool (thr_pool);if (0) {/* If you run acl_pthread_pool_destroy now, Because the thread pool destruction function is called, * the main thread immediately notifies the idle thread to exit, all idle threads do not have to wait for an idle timeout to exit, */printf ("> wait all threads to be idle and free thread pool\r\n ");/* immediately destroys the thread pool */acl_ Pthread_pool_destroy (Thr_pool);} else {/* because acl_pthread_pool_destroy is not called immediately, all idle threads exit after the idle * timeout period arrives */ while (1) {int ret;ret = acl_pthread_pool_size (Thr_pool);if (ret == 0) break;printf ("> current threads in thread pool is:&nbSp;%d\r\n ", ret); sleep (1);} The number of worker threads in the/* thread pool is 0 o'clock destroys the thread pool */printf ("> all worker thread exit now\r\n"); acl_ Pthread_pool_destroy (Thr_pool);} /* main thread waits for the user to enter any word specifier exit */printf ("> enter any key to exit\r\n") at the terminal; GetChar () ;return (0);}
3.2) Compile Links
Download Acl_project code from http://www.sourceforge.net/projects/acl/site, under WIN32 platform, please VC2003 compile, open acl_project\win32_build\vc\ Acl_project_vc2003.sln generates lib_acl_vc2003.lib under directory Acl_project\dist\lib_acl\lib\win32 after compilation, and then includes the library in the console project of the sample and includes Acl_ Project\lib_acl\include under the lib_acl.h header file, compile the above source code can be.
Because this example code is in the ACL example, it is possible to compile the Thread_pool project in Acl_project\win32_build\vc\samples\samples_vc2003.sln directly.
3.3) Run
After running the sample program, the results of the display on my machine are as follows:
On_thread_init:thread (23012) init now
Thread start! tid=23012, I=0, __local=0
Thread start! tid=23012, I=0, __local=1
> Current threads in thread pool Is:2
On_thread_init:thread (23516) init now
Thread start! tid=23516, I=1, __local=0
Thread start! tid=23516, I=1, __local=1
> Current threads in thread pool Is:2
Thread start! tid=23012, I=0, __local=2
Thread start! tid=23516, I=1, __local=2
Thread start! tid=23012, I=0, __local=3
> Current threads in thread pool Is:2
Thread start! tid=23516, I=1, __local=3
Thread start! tid=23012, I=0, __local=4
> Current threads in thread pool Is:2
Thread start! tid=23516, I=1, __local=4
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
> Current threads in thread pool Is:2
On_thread_exit:thread (23012) Exit now
> Current threads in thread pool is:1
On_thread_exit:thread (23516) Exit now
> All worker thread exit now
> enter any key to exit
Iv. Summary
As can be seen, the use of ACL library to create semi-resident high concurrent multithreaded program is relatively simple, ACL line Cheng interface definition and implementation as far as possible POSIX thread implementation of the interface is similar, the steps to create and use ACL line Cheng are as follows:
A) Acl_pthread_pool_attr_init: Initializes the attribute information required to create the thread pool object (you can set the maximum number of concurrent threads in the Acl_pthread_pool_attr_set_threads_limit and Acl_ Pthread_pool_attr_set_idle_timeout set the idle exit interval for worker threads in the thread pool
b) acl_pthread_pool_create: Create thread Pool Object
c) Acl_pthread_pool_add: Add a new task to the thread pool, and the new task will be executed by a worker thread in the thread pool
d) Acl_pthread_pool_destroy: Notifies and waits for a worker thread in the thread pool to exit after the task has finished executing and destroys the thread pool object
You can also call the Acl_pthread_pool_atinit setting when the worker thread is created the first time when the thread pool object is created, callback the user-defined Function procedure, or call the callback function set in Acl_pthread_pool_atfree when the threads are idle.
In addition, the process of creating a thread pool can be abstracted in the following form:
/** * Creating a semi-resident thread pool process * @return {acl_pthread_pool_t*} newly created thread pool handle */static acl_pthread_pool_t *create_thread_pool (void) {Acl_ pthread_pool_t *thr_pool; /* thread pool handle */int max_threads = 100; /* Maximum concurrent 100 threads */int idle_timeout = 10; /* Automatically exit */acl_pthread_pool_attr_t attr after each worker thread has been idle for 10 seconds; /* Properties *//* initialization of thread pool initialization thread pool object Properties */acl_pthread_pool_attr_init (&attr); Acl_pthread_pool_attr_set_threads_limit ( &attr, max_threads); Acl_pthread_pool_attr_set_idle_timeout (&attr, idle_timeout);/* Create semi-resident thread handle */thr_pool = Acl_pthread_pool_create (&attr); assert (Thr_pool); return (Thr_pool);}
In fact, the use of ACLs to create a thread pool also has a simplified interface (so called acl_thread_xxx not add p, because this interface does not adhere to some of the POSIX specifications), as follows:
/** * Easier way to create thread objects * @param threads_limit {int} thread pool maximum number of concurrent threads * @param idle_timeout {int} worker thread idle timeout exit time (seconds), if 0 worker thread never quits * The @return {acl_pthread_pool_t*}, if not NULL, indicates success, otherwise fails */ACL_API acl_pthread_pool_t *acl_thread_pool_create (int threads_ Limit, int idle_timeout);
This makes it easy for users to create their own thread pools, and don't forget that the thread pool can be semi-resident (and, of course, cross-platform, and can run in linux/solaris/freebsd/win32 environments).
To facilitate the use of ACL libraries, users can refer to the online Help documentation for ACLs: Http://acl.sourceforge.net/acl_help/index.html.
Personal micro-Blog: http://weibo.com/zsxxsz
Download: http://sourceforge.net/projects/acl/
Svn:svn://svn.code.sf.net/p/acl/code/trunk
Github:https://github.com/zhengshuxin/acl
QQ Group: 242722074
Using the C Library of the ACL library to write multithreaded threads