Weekend saw the Nginx thread pool part of the code, copied it again, written in its own version. Some areas of implementation are still different, but the basic structure is all excerpt.
Share it here. If you understand my version, it will prove that you understand the nginx thread pool.
This article only lists the key data structures and APIs, and focuses on understanding the nginx thread pool design ideas. The complete code is in the final link.
1. Task node
void (*cb_fun) (void *); // Task Structure Body struct task{ void // task function parameters (to ensure that the parameter address is valid before the task execution ends) cb_fun Task function (the return value must be a value of 0 not 0 for increasing threads, and destroying the thread pool) struct// task chain Pointer } zoey_task_t;
Handler is a function pointer, is the actual task function, argv is the parameter of the function, next points to the next task.
2. Task Queue
struct task_queue{ *head; // Queue Header zoey_task_t **tail; // End of queue int // Maximum task limit int // Current number of tasks } zoey_task_queue_t;
Head is the task queue header pointer, tail is the task queue tail pointer, Maxtasknum is the maximum queue task limit, Curtasknum is the queue current task count.
3. Thread pool
struct threadpool{ pthread_mutex_t mutex; // Mutual exclusion Lock pthread_cond_t cond; // Conditional Lock zoey_task_queue_t tasks; task queue int // number of threads int // thread stack size }zoey_threadpool_t;
The mutex is the mutex cond for the conditional lock. Mutexes and cond together ensure that the thread pool task is mutually exclusive to pick up or add.
Tasks points to the task queue.
Threadnum number of threads for the thread pool
Thread_stack_size for thread stack size
4. Start the configuration
// Configuration Parameters struct threadpool_conf{ int threadnum; // Number of threads int thread_stack_size; // thread stack size int maxtasknum; // Maximum task limit } zoey_threadpool_conf_t;
Starting the configuration structure body is some of the parameters when the thread pool is initialized.
5. Initializing the thread pool
First check that the arguments are valid, and then initialize Mutex,cond,key (pthread_key_t). Key is used to read and write thread global variables, and this global variable controls whether the thread exits.
Finally, the thread is created.
zoey_threadpool_t* Zoey_threadpool_init (zoey_threadpool_conf_t *conf) {zoey_threadpool_t*pool =NULL; intError_flag_mutex =0; intError_flag_cond =0; pthread_attr_t attr; Do{ if(Z_conf_check (conf) = =-1){//Check if the parameters are legitimate Break; } Pool= (zoey_threadpool_t *)malloc(sizeof(zoey_threadpool_t));//apply thread pool handle if(Pool = =NULL) { Break; } //initialize thread pool basic parametersPool->threadnum = conf->Threadnum; Pool->thread_stack_size = conf->thread_stack_size; Pool->tasks.maxtasknum = conf->Maxtasknum; Pool->tasks.curtasknum =0; Z_task_queue_init (&pool->tasks); if(Z_thread_key_create ()! =0){//Create a pthread_key_t to access the thread global variables. Free(pool); Break; } if(Z_thread_mutex_create (&pool->mutex)! =0){//Initialize Mutex lockZ_thread_key_destroy (); Free(pool); Break; } if(Z_thread_cond_create (&pool->cond)! =0){//initializing a conditional lockZ_thread_key_destroy (); Z_thread_mutex_destroy (&pool->mutex); Free(pool); Break; } if(Z_threadpool_create (pool)! =0){//Create a thread poolZ_thread_key_destroy (); Z_thread_mutex_destroy (&pool->mutex); Z_thread_cond_destroy (&pool->cond); Free(pool); Break; } returnPool; } while(0); returnNULL;}
6. Add a task
First, request a task node, instantiate it, join the node to the task queue, and notify the other processes of new tasks by adding the current task queue. Lock the whole process.
intZoey_threadpool_add_task (zoey_threadpool_t *pool, Cb_fun handler,void*argv) {zoey_task_t*task =NULL; //Request a Task node and assign a valueTask = (zoey_task_t *)malloc(sizeof(zoey_task_t)); if(Task = =NULL) { return-1; } Task->handler =handler; Task->ARGV =argv; Task->next =NULL; if(Pthread_mutex_lock (&pool->mutex)! =0){//Locking Free(Task); return-1; } Do{ if(Pool->tasks.curtasknum >= Pool->tasks.maxtasknum) {//determine if the number of tasks in the work queue is up to limit Break; } //to end a task node in a task queue* (Pool->tasks.tail) =task; Pool->tasks.tail = &task->Next; Pool->tasks.curtasknum++; //notifies the blocked thread if(Pthread_cond_signal (&pool->cond)! =0){ Break; } //UnlockPthread_mutex_unlock (&pool->mutex); return 0; } while(0); Pthread_mutex_unlock (&pool->mutex); Free(Task); return-1;}
7. Destroying the thread pool
Destroying the thread pool is also adding tasks to the task queue, but adding the task is to have the thread exit. The Z_THREADPOOL_EXIT_CB function will lock 0 back out of the thread, and a lock of 0 indicates that it
Has exited and then exits the next thread. The thread frees all resources after exiting.
voidZoey_threadpool_destroy (zoey_threadpool_t *pool) {unsignedintn =0; volatileUnsignedint Lock; //the Z_THREADPOOL_EXIT_CB function causes the corresponding thread to exit for(N < pool->threadnum; n++){ Lock=1; if(Zoey_threadpool_add_task (Pool, Z_THREADPOOL_EXIT_CB, &Lock) !=0){ return; } while(Lock) {Usleep (1); }} Z_thread_mutex_destroy (&pool->mutex); Z_thread_cond_destroy (&pool->cond); Z_thread_key_destroy (); Free(pool);}
8. Add a thread
It is simple to generate a thread and the number of threads + +. Locking
int zoey_thread_add (zoey_threadpool_t *pool) { int0; if 0 ) { return -1; } = Z_thread_add (pool); Pthread_mutex_unlock (&pool->mutex); return ret;}
9. Change task Queue maximum task limit
When Num=0 is set, the number of threads is infinitely large.
void int num) { if0) { return -1; } Z_change_maxtask_num (pool, num); // Change the maximum task limit Pthread_mutex_unlock (&pool->mutex);}
usage Examples
intMain () {intarray[10000] = {0}; inti =0; zoey_threadpool_conf_t conf= {5,0,5};//Instantiating startup Parameterszoey_threadpool_t *pool = Zoey_threadpool_init (&conf);//initializing the thread pool if(Pool = =NULL) { return 0; } for(; I <10000; i++) {Array[i]=i; if(i = = the) {zoey_thread_add (pool);//Increase Threadzoey_thread_add (pool); } if(i = = -) {zoey_set_max_tasknum (pool,0);//Change Maximum task number 0 to do not limit } while(1){ if(Zoey_threadpool_add_task (pool, Testfun, &array[i]) = =0){ Break; } printf ("error in i =%d\n", i); }} Zoey_threadpool_destroy (pool); while(1) {Sleep (5); } return 0;}
One. Source Code
HTTPS://github.com/unlikewashface/zoey_threadpool.git
Analysis of Nginx line Cheng code