Implementation of a C thread pool in Linux)

Source: Internet
Author: User

1. Basic principles of Thread Pool

In the traditional server structure, there is often a general listening thread that listens to whether there are new users connecting to the server. Whenever a new user enters, the server starts a new thread user to process the user's data packets. This thread only serves this user. When the user closes the connection with the server, the server destroys this thread. However, frequent thread opening and destruction greatly occupy system resources. In addition, in the case of a large number of users, the system will waste a lot of time and resources to open up and destroy threads. The thread pool provides a solution to the conflict between a large number of external users and limited resources on the server. The thread pool corresponds to a traditional user
Different threads have different processing methods. The basic idea is to open some threads in the memory at the beginning of the program. The number of threads is fixed and they form a class independently, the external operations are blocked, and the server only needs to deliver the data packet to the thread pool. When a new customer request arrives, instead of creating a new thread to serve it, it selects an idle thread from the pool to serve the new customer request. After the service is completed, the thread enters the idle thread pool. If there is no thread idle, the data packet will be accumulated temporarily, and will be processed after there is thread idle in the thread pool. By reusing existing thread objects for multiple tasks, the overhead of creating and destroying thread objects is reduced. When a customer requests
When the thread object has been stored, the response time can be improved to improve the overall performance of the system service.

Generally, implementing a thread pool mainly includes the following components:

1) thread MANAGER: used to create and manage thread pools.

2) Worker thread: the thread that actually executes the task in the thread pool. During thread initialization, a fixed number of threads are created in the pool in advance. These initialization threads are generally idle and generally do not occupy the CPU and occupy a small amount of memory.

3) task interface: the interface that each task must implement. When the task queue in the thread pool has executable tasks, it is called and executed by idle working threads (the idle and busy threads are achieved through mutex, which is similar to the flag set in the previous article). The tasks are abstracted to form interfaces, the thread pool is independent of a specific task.

4) task queue: it is used to store unprocessed tasks and provides a buffer mechanism. There are several methods to achieve this structure. Queues are commonly used, mainly based on the principle of first-in-first-out, another type is the data structure such as the linked list, which can dynamically allocate memory space for it and be flexible in applications. The linked list is used below.

The following is not a detailed description of Baidu's application of thread pool technology in concurrent servers!

From: http://blog.csdn.net/zouxinfox/article/details/3560891

When do I need to create a thread pool? Simply put, if an application requires frequent thread creation and destruction, and the task execution time is very short, the overhead of thread creation and destruction cannot be ignored, this is also the opportunity for the thread pool to play. If the task execution time is negligible compared with the thread creation and destruction time, there is no need to use the thread pool.

The following is a thread pool created in C language in Linux. The thread pool maintains a task linked list (each cthread_worker structure is a task ).
The pool_init () function creates max_thread_num threads in advance, and each thread runs the thread_routine () function. In this function

  1. While (pool-> cur_queue_size = 0)
  2. {
  3. Pthread_cond_wait (& (pool-> queue_ready), & (pool-> queue_lock ));
  4. }

Indicates that if no task exists in the task Link Table, the thread waits for blocking. Otherwise, the task is retrieved from the queue and executed.

Pool_add_worker () function adds a task to the task chain table of the thread pool. After adding the task, call pthread_cond_signal (& (pool-> queue_ready) by calling pthread_cond_signal )) wake up a thread in the blocking status (if any ).

The pool_destroy () function is used to destroy the thread pool. Tasks in the linked list of tasks in the thread pool are not executed again, but the running thread keeps running the task and then exits.

# Include <stdio. h> # include <stdlib. h> # include <unistd. h> # include <sys/types. h> # include <pthread. h> # include <assert. h>/** all running and waiting tasks in the thread pool are a cthread_worker * because all tasks are in the linked list, therefore, it is a linked list structure */typedef struct worker {/* callback function. This function is called when the task is running. Note that it can be declared as another form */void * (* process) (void * Arg); void * ARG;/* callback function parameter */struct worker * Next;} cthread_worker;/* Thread Pool Structure */typedef struct {pthread_mutex_t queue_lock; pthread_cond_t queue_ready; /* Linked list structure, all waiting tasks in the thread pool */cthread_worker * queue_head;/* Whether to destroy the thread pool */INT shutdown; pthread_t * threadid; /* Number of active threads allowed in the thread pool */INT max_thread_num;/* Number of tasks waiting for the queue */INT cur_queue_size;} cthread_pool; int pool_add_worker (void * (* process) (void * Arg), void * Arg); void * thread_routine (void * Arg); // share resourcestatic cthread_pool * Pool = NULL; voidpool_init (INT max_thread_num) {pool = (cthread_pool *) malloc (size Of (cthread_pool); pthread_mutex_init (& (pool-> queue_lock), null); pthread_cond_init (& (pool-> queue_ready), null); pool-> queue_head = NULL; pool-> max_thread_num = max_thread_num; pool-> cur_queue_size = 0; pool-> shutdown = 0; pool-> threadid = (pthread_t *) malloc (max_thread_num * sizeof (pthread_t )); int I = 0; for (I = 0; I <max_thread_num; I ++) {pthread_create (& (pool-> threadid [I]), null, THR Ead_routine, null) ;}}/* add tasks to the thread pool */intpool_add_worker (void * (* process) (void * Arg), void * Arg) {/* construct a new task */cthread_worker * newworker = (cthread_worker *) malloc (sizeof (cthread_worker); newworker-> process = process; newworker-> Arg = ARG; newworker-> next = NULL;/* do not forget to leave it blank */pthread_mutex_lock (& (pool-> queue_lock )); /* Add the task to the waiting queue */cthread_worker * member = pool-> queue_head; If (member! = NULL) {While (member-> next! = NULL) member = Member-> next; Member-> next = newworker;} else {pool-> queue_head = newworker;} assert (pool-> queue_head! = NULL); pool-> cur_queue_size ++; pthread_mutex_unlock (& (pool-> queue_lock);/* OK, wait for a task in the queue and wake up a waiting thread; note that if all threads are busy, this statement does not work */pthread_cond_signal (& (pool-> queue_ready); Return 0 ;}/ * destroy the thread pool, tasks in the waiting queue will not be executed again, but the running thread will keep running the task and then exit */intpool_destroy () {If (pool-> shutdown) Return-1; /* prevent two calls */pool-> shutdown = 1;/* wake up all the waiting threads, and the thread pool will destroy */pthread_cond_broadcast (& (pool-> queue_ready )); /* blocking waits for the thread to exit, otherwise it will become a zombie */int I; for (I = 0; I <pool-> max_thread_num; I ++) pthread_join (pool-> threadid [I], null); free (pool-> threadid ); /* destroy wait queue */cthread_worker * head = NULL; while (pool-> queue_head! = NULL) {head = pool-> queue_head; pool-> queue_head = pool-> queue_head-> next; free (head );} /* do not forget to destroy condition variables and mutex values */pthread_mutex_destroy (& (pool-> queue_lock); pthread_cond_destroy (& (pool-> queue_ready); free (pool ); /* setting the pointer to null after destruction is a good habit */pool = NULL; return 0;} void * thread_routine (void * Arg) {printf ("Starting thread 0x % x \ n", pthread_self (); While (1) {pthread_mutex_lock (& (pool-> queue_lock )); /* If the waiting queue is 0 If the thread pool is not destroyed, it is in the blocking state. Note that pthread_cond_wait is an atomic operation and will be unlocked before waiting, lock */while (pool-> cur_queue_size = 0 &&! Pool-> shutdown) {printf ("thread 0x % x is waiting \ n", pthread_self (); pthread_cond_wait (& (pool-> queue_ready ), & (pool-> queue_lock);}/* The thread pool has to be destroyed */If (pool-> shutdown) {/* Jump statements, such as break, continue, and return, never forget to unlock */pthread_mutex_unlock (& (pool-> queue_lock); printf ("thread 0x % x will exit \ n", pthread_self ()); pthread_exit (null);} printf ("thread 0x % x is starting to work \ n", pthread_self ();/* SERT is a good helper for debugging */assert (pool-> cur_queue_size! = 0); Assert (pool-> queue_head! = NULL);/* Wait for the queue length minus 1, and retrieve the Header element in the linked list */pool-> cur_queue_size --; cthread_worker * worker = pool-> queue_head; pool-> queue_head = worker-> next; pthread_mutex_unlock (& (pool-> queue_lock);/* call the callback function and execute the task */(* (worker-> process )) (worker-> Arg); free (worker); worker = NULL;}/* this sentence should be inaccessible */pthread_exit (null );} // The following is the test code void * myprocess (void * Arg) {printf ("threadid is 0x % x, working on task % d \ n", pthread_self (), * (int *) Arg); sleep (1);/* rest for one second to prolong the task execution time */return NULL;} intmain (INT argc, char ** argv) {pool_init (3);/* a maximum of three active threads in the thread pool * // * adds 10 tasks to the pool consecutively */int * workingnum = (int *) malloc (sizeof (INT) * 10); int I; for (I = 0; I <10; I ++) {workingnum [I] = I; pool_add_worker (myprocess, & workingnum [I]);}/* wait for all tasks to be completed */sleep (5);/* destroy thread pool */pool_destroy (); free (workingnum ); return 0 ;}


Put all the above Code into the threadpool. c file,
Enter the compilation command in Linux
$ Gcc-O threadpool. C-lpthread

The following are the running results:
Starting thread 0xb7df6b90
Thread 0xb7df6b90 is waiting
Starting thread 0xb75f5b90
Thread 0xb75f5b90 is waiting
Starting thread 0xb6df4b90
Thread 0xb6df4b90 is waiting
Thread 0xb7df6b90 is starting to work
Threadid is 0xb7df6b90, working on task 0
Thread 0xb75f5b90 is starting to work
Threadid is 0xb75f5b90, working on Task 1
Thread 0xb6df4b90 is starting to work
Threadid is 0xb6df4b90, working on Task 2
Thread 0xb7df6b90 is starting to work
Threadid is 0xb7df6b90, working on Task 3
Thread 0xb75f5b90 is starting to work
Threadid is 0xb75f5b90, working on Task 4
Thread 0xb6df4b90 is starting to work
Threadid is 0xb6df4b90, working on Task 5
Thread 0xb7df6b90 is starting to work
Threadid is 0xb7df6b90, working on Task 6
Thread 0xb75f5b90 is starting to work
Threadid is 0xb75f5b90, working on task 7
Thread 0xb6df4b90 is starting to work
Threadid is 0xb6df4b90, working on task 8
Thread 0xb7df6b90 is starting to work
Threadid is 0xb7df6b90, working on task 9
Thread 0xb75f5b90 is waiting
Thread 0xb6df4b90 is waiting
Thread 0xb7df6b90 is waiting
Thread 0xb75f5b90 will exit
Thread 0xb6df4b90 will exit
Thread 0xb7df6b90 will exit

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.