Simple thread pool Implementation (C version)

Source: Internet
Author: User

1. Overview

Before we talk about the thread pool, let's look at the different ways in which concurrency is possible.

multiple processes , including the process of starting multiple processes at once, then passing descriptors between processes, or connecting to later fork process.

multithreading , the same can be like a multi-process, or build a stack there, or there is a connection after the "instant build, Instant destruction"

There is nothing wrong with the way we see it, and special scenes can always be useful.

For example, if a concurrency is only two digits or even single digits, then the above methods are easy to deal with. But if you want to cite an extreme example, 100,000 of concurrent, it is impossible to establish 100,000 processes in the first place waiting for this concurrency, it is impossible to create instant destruction. All of which adds to the burden of the system.

Consider a problem that may be 10W concurrent, and the service for each connection request is ended in just 1 seconds or less. The above approach is obviously a bit of an extensive one for this scenario. This time, we need a concurrency that can cope with high concurrency and not eat resources as well. Then the thread pool stands out.

2. Design

The thread pool, as its name implies, is a pool that puts a bunch of threads inside. When it's all right, all shifty, gearing up, and who's going to get the count.

So how does the thread pool do it?

1. Entrance

As stated above, the thread pool is a bunch of threads in a pool, so the question is, how to make sure that these threads are quiet when they are all right. Simple mutexes do not do this and need to combine cond to achieve this effect.

        Pthread_mutex_lock (Pthread_pool->pmutex);        While avoiding spurious wake while        (Pthread_pool->pthread_job->job_num = = 0 && 0 = = Pthread_pool->need_destroy)        {            pthread_cond_wait (Pthread_pool->pcond, Pthread_pool->pmutex);        }
This will ensure that the thread will not be in trouble when it's OK. Here is an explanation of the function of the while, as noted in the note, to avoid false wakes, which may not be pthread_cond_signal or pthread_cond_broadcast not invoked, But the thread still returns from Pthread_cond_wait, and if there is no while this judgment, the thread will always go wrong, which is obviously not what we want to see.

2. Task Assignment

There is no doubt that we have to use callbacks to achieve the assignment of tasks. This callback function can completely simulate the callback of the thread itself.

ARGV The specified address is released by the thread pool typedef struct tag_job{    THREAD_CB cb;    void *argv;    struct Tag_job *next;} job_t, *job_pt;typedef struct{    int32_t job_num;    JOB_PT head;    JOB_PT tail;} thread_job_t, *thread_job_pt;
For the thread pool, the task must be a queue, or it can be understood as a task pool, and any awakened thread will go to the pool and fetch a task. Then execute. Continue to sleep after execution.

3. Destruction

First of all, I have encountered the problem, I used a number of methods of destruction today, the facts proved to be wrong. Finally, I can find some examples from the network. Ashamed.

Error A. Call Pthread_cancel directly, if a thread is stuck in cond there, you can't destroy it in this way, and if it happens to be working, then you successfully destroy it, it's better not destroyed because of the deadlock.

Error B. Use Pthread_kill to send the Sigkill. Then the entire program is then hung up. Finally, the signal is shared within the process. If you do not want to be exited abnormally, capture the signal in the main thread. And then the online pool has a corresponding signal processing function. Of course, This signal is definitely not sigstop and Sigkill.

Error C. Release the mutex and cond directly after the pthread_cond_broadcast. You know, the thread pool may not have the main thread to exit fast, that is, the main thread has already freed the cond and the mutex, and the thread pool has not successfully exited threads, At this point it is possible to call unlock or lock, regardless of which causes the program to crash unexpectedly.

Well, say the right thing, after Broad, wait to confirm that all threads exit, and then release cond and mutexes. This will make the program work.

In my thread pool, I added a master, that is, if you create a 10-thread pool, my line pool creates 11 threads, and the 11th thread is used to keep alive, if a thread in the thread pool is going to return a logical exception. You need this thread to restart it. ...

3. Implement

Thread.h

/*!**************************************************************************** * Coypright (C) 2014-2024 () Technology Co., LTD * * File name: Thread.h * Version Number: 1.0 * Description: Thread pool Implementation * Author: Cp3alai * Date: 2016.05.31 ******************* /#include <unistd.h> #include <stdlib.h># Include <stdint.h> #include <string.h> #include <pthread.h> #include <signal.h> #include <    errno.h>typedef void (*THREAD_CB) (void *argv);//argv The specified address is released by the thread pool typedef struct tag_job{THREAD_CB CB;    void *argv; struct Tag_job *next;}    job_t, *job_pt;typedef struct{int32_t job_num;    JOB_PT Head; JOB_PT tail;} thread_job_t, *thread_job_pt;int thread_job_init (thread_job_pt *pthread_job); int Thread_job_push (thread_job_pt Thread_job, THREAD_CB cb, void *arg) job_pt thread_job_pop (thread_job_pt thread_job); void Thread_job_destroy (Thread_    Job_pt thread_job); typedef struct{INT32_T Need_destroy;    int32_t Thread_num; Pthread_t Pthread_master;    pthread_t *pthread_id;    Thread_job_pt Pthread_job;    pthread_cond_t *pcond; pthread_mutex_t *pmutex;} thread_pool_t, *thread_pool_pt;int Pthread_create_detach (pthread_t *thread, void * (*start_routine) (void*), void *arg) void *thread_entry (void *arg); void *thread_master (void *arg); int Thread_pool_init (thread_pool_t **pthread_pool, int num); int Thread_pool_add (Thread_pool_pt pthread_pool, thread_cb, void *arg); int thread_pool_kill (); int Thread_pool_ KeepAlive (); void Thread_pool_destroy (Thread_pool_pt pthread_pool);

Thread.c

/*!**************************************************************************** * Coypright (C) 2014-2024 ()  Technology Co., LTD * * File name:/MEDIA/ALAI/WORK/WORKSPACE/CC++/MRTPOLL/THREAD.C * Version Number: 1.0 * Description: * Author: Cp3alai * Day Period: 2016.05.31 *****************************************************************************/#include "thread.h"    int Thread_job_init (thread_job_pt *pthread_job) {int32_t ret;        if (NULL = = pthread_job) {ret =-1;    Goto ERROR;    } *pthread_job = (thread_job_pt) malloc (sizeof (thread_job_t));        if (NULL = = *pthread_job) {ret =-1;    Goto ERROR;    } bzero (*pthread_job, sizeof (thread_job_t));    (*pthread_job)->head = NULL;    (*pthread_job)->tail= NULL; ret = 0; Error:return ret;}    int Thread_job_push (thread_job_pt thread_job, THREAD_CB cb, void *arg) {int32_t ret = 0;    Job_pt pjob = NULL; if (NULL = = Thread_job | |        NULL = = cb) {ret =-1;    Goto ERROR; } pjob = (job_pt) malloc (SizeoF (job_t));        if (NULL = = pjob) {ret =-1;    Goto ERROR;    } pjob->argv = arg;    PJOB-&GT;CB = CB;    Pjob->next = NULL;        if (NULL! = thread_job->head) {thread_job->tail->next = Pjob;    Thread_job->tail = Pjob;        } else {thread_job->head = Pjob;    Thread_job->tail = Pjob; } thread_job->job_num++; Error:return ret;}    The job returned here needs to use its thread to release job_pt Thread_job_pop (thread_job_pt thread_job) {job_pt job = NULL;    if (null = = Thread_job) {return null;    } if (null = = Thread_job->head) {return null;    } job = thread_job->head;    Thread_job->head = thread_job->head->next;    thread_job->job_num--; return job;}    void Thread_job_destroy (Thread_job_pt thread_job) {if (NULL = = thread_job) {return;        } while (NULL! = thread_job->head) {job_pt pjob = thread_job->head;        Thread_job->head = pjob->next; FreePjob);    Pjob = NULL;    } free (thread_job);    Thread_job = NULL; return;}    int Pthread_create_detach (pthread_t *thread, void * (*start_routine) (void*), void *arg) {pthread_attr_t attr;    Pthread_attr_init (&AMP;ATTR);    Pthread_attr_setdetachstate (&attr, 1); return pthread_create (thread, &attr, Start_routine, ARG);}    void *thread_master (void *arg) {if (null = = arg) {return null;    } thread_pool_pt Pthread_pool = (thread_pool_pt) arg;    int i; while (1) {for (i = 0; i < pthread_pool->thread_num; i++) {if (0 = = Pthread_pool->p Thread_id[i]) {Pthread_create_detach (&pthread_pool->pthread_id[i], Thread_entry, (void*)            Pthread_pool);                 } if ((Pthread_kill (Pthread_pool->pthread_id[i], 0) < 0) {if (errno = = Esrch) {Pthread_create_detach (&pthread_pool->pthread_id[i], Thread_entry, (void*)Pthread_pool);        }} sleep (1); }} return NULL;}    void *thread_entry (void *arg) {if (null = = arg) {return null;    } thread_pool_pt Pthread_pool = (thread_pool_pt) arg;        while (1) {pthread_mutex_lock (Pthread_pool->pmutex); It is also possible to avoid false wakeup//while (Pthread_cond_wait (Pthread_pool->pcond, Pthread_pool->pmutex)) while (Pthre Ad_pool->pthread_job->job_num = = 0 && 0 = Pthread_pool->need_destroy) {Pthread_cond_w        AIT (Pthread_pool->pcond, Pthread_pool->pmutex); }//If the thread is destroyed, exit the IF (0! = Pthread_pool->need_destroy) {pthread_pool->thread_num-            -;            Pthread_mutex_unlock (Pthread_pool->pmutex);        Break        } job_pt pjob = Thread_job_pop (pthread_pool->pthread_job);        if (NULL = = Pjob) {continue; } pthread_mutex_unlock (Pthread_pool->pMutex);        PJOB-&GT;CB (PJOB-&GT;ARGV);        Run out to release ... free (pjob);    Pjob = NULL; } return NULL;    int Thread_pool_init (thread_pool_t **pthread_pool, int num) {int ret = 0;    int i;        if (NULL = = Pthread_pool | | 0 = = num) {ret =-1;    Goto ERROR;    } *pthread_pool = (thread_pool_pt) malloc (sizeof (thread_pool_t));        if (NULL = = *pthread_pool) {ret =-1;    Goto ERROR;    } bzero ((*pthread_pool), sizeof (thread_pool_t));    (*pthread_pool)->pmutex = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));        if (NULL = = (*pthread_pool)->pmutex) {ret =-1;    Goto ERROR;    } (*pthread_pool)->pcond = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));        if (NULL = = (*pthread_pool)->pcond) {ret =-1;    Goto ERROR;    } pthread_mutex_init ((*pthread_pool)->pmutex, NULL);    Pthread_cond_init ((*pthread_pool)->pcond, NULL); if (ret = Thread_job_init (& (*pthread_pool)->pthread_job)) < 0) {ret =-1;    Goto ERROR;    } (*pthread_pool)->pthread_id = (pthread_t*) malloc (num * sizeof (pthread_t));        if (NULL = = (*pthread_pool)->pthread_id) {ret =-1;    Goto ERROR;    } bzero ((*pthread_pool)->pthread_id, sizeof (pthread_t) * num);    (*pthread_pool)->thread_num = num;  for (i = 0; i < num; i++) {ret = Pthread_create_detach (& (*pthread_pool)->pthread_id[i], Thread_entry, (void *)        (*pthread_pool));        if (Ret < 0) {(*pthread_pool)->pthread_id[i] = 0;    }} ret = Pthread_create_detach (& (*pthread_pool)->pthread_master, Thread_master, (void *) (*pthread_pool));        if (Ret < 0) {ret =-1;    Goto ERROR; } ret = 0; Error:if (Ret < 0) {if (NULL! = (*pthread_pool)) {Thread_pool_destroy (*pthread_pool)        ); }} return ret;} int Thread_pool_add (thread_pool_pt pthread_pool, THREAD_CB CB, void *arg) {int32_t ret = 0; if (NULL = = Pthread_pool | |        NULL = = cb) {ret =-1;    Goto ERROR;        } if (NULL = = pthread_pool->pthread_job) {ret =-1;    Goto ERROR;    } pthread_mutex_lock (Pthread_pool->pmutex);    ret = Thread_job_push (pthread_pool->pthread_job, CB, ARG);        if (Ret < 0) {ret =-1;    Goto ERROR;    } pthread_cond_signal (Pthread_pool->pcond);    Pthread_mutex_unlock (Pthread_pool->pmutex); ret = 0; Error:return ret;}    int Thread_pool_kill (thread_pool_pt pthread_pool, int32_t thread_no, int32_t signo) {int32_t ret;    int32_t i;        if (NULL = = Pthread_pool) {ret =-1;    Goto ERROR; } if (0 = = Thread_no) {for (i = 0; i < pthread_pool->thread_num; i++) {Pthread_kill        (Pthread_pool->pthread_id[i], signo);        }} else {ret = Pthread_kill (Pthread_pool->pthread_id[thread_no], signo);   if (Ret < 0)     {ret =-1;        Goto ERROR; }} ret = 0; Error:return ret;}    int thread_pool_keepalive (thread_pool_pt pthread_pool) {int32_t ret;    int32_t i;    if (NULL = = Pthread_pool) {return-1; } for (i = 0; i < pthread_pool->thread_num; i++) {ret = Pthread_kill (Pthread_pool->pthread_id[i], 0        ); if (Ret < 0) {if (errno = = Esrch) {Pthread_create_detach (&pthread_poo            L->pthread_id[i], thread_entry, (void *) pthread_pool); }}} return 0;}    void Thread_pool_destroy (Thread_pool_pt pthread_pool) {int32_t i;    if (NULL = = Pthread_pool) {return;    } if (0! = pthread_pool->pthread_master) {pthread_cancel (pthread_pool->pthread_master);        } if (NULL! = pthread_pool->pthread_id) {Pthread_pool->need_destroy = 1;        Pthread_cond_broadcast (Pthread_pool->pcond); Free (pthread_pool->PTHREAD_ID);    pthread_pool->pthread_id = NULL;    } if (NULL! = pthread_pool->pthread_job) {Thread_job_destroy (pthread_pool->pthread_job);    }//wait for thread to finish destroying while (Pthread_pool->thread_num > 0) {usleep (0);        } if (NULL! = Pthread_pool->pmutex) {Pthread_mutex_destroy (Pthread_pool->pmutex);        Free (Pthread_pool->pmutex);    Pthread_pool->pmutex = NULL;        } if (NULL! = Pthread_pool->pcond) {Pthread_cond_destroy (Pthread_pool->pcond);        Free (Pthread_pool->pcond);    Pthread_pool->pcond = NULL; }}

Main.c

#include <stdio.h> #include "thread.h" void thread_routine1 (void *argv) {fprintf (stderr, "This is Thread 1\n"); return;}    void Thread_routine2 (void *argv) {fprintf (stderr, "This is Thread 2\n"); return;}    int main (int argc, char **argv) {int32_t ret;    Thread_pool_pt Pthread_pool;    ret = Thread_pool_init (&pthread_pool, 30);    if (Ret < 0) {return-1;    } thread_pool_add (Pthread_pool, Thread_routine1, NULL);    Thread_pool_add (Pthread_pool, Thread_routine2, NULL);    Thread_pool_add (Pthread_pool, Thread_routine2, NULL);    Thread_pool_add (Pthread_pool, Thread_routine2, NULL);    Thread_pool_add (Pthread_pool, Thread_routine2, NULL);    Thread_pool_add (Pthread_pool, Thread_routine2, NULL);    Thread_pool_add (Pthread_pool, Thread_routine1, NULL);    Thread_pool_add (Pthread_pool, Thread_routine1, NULL);    Thread_pool_add (Pthread_pool, Thread_routine1, NULL);    Thread_pool_add (Pthread_pool, Thread_routine1, NULL);    Sleep (5); Thread_pool_destroy(Pthread_pool);    Sleep (5); return 0;}
Simple. Makefile
##################################################### #Make with me############################################## # # # # #CC: = gcctarget: = pool_testobj: = MAIN.O Thread.oincs: =-i.libs: =-lpthreadcflags: =-ggdb3-o0$ (TARGET): $ (OBJ) $ (CC)-O $ (TARGET) $ (OBJ) $ (CFLAGS) $ (INCS) $ (LIBS). Phony:cleanclean: @echo "cleaned" @rm-RF $ (TARGET) $ (OBJ)

Execution Result:


4. PostScript

Write to the end, in fact, this blog has another purpose, is to hope that you see the students, if there is a problem in the code, please help to point out in the comments. Really appreciate it.


Simple thread pool Implementation (C version)

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.