Simple implementation of C language thread pool __c language

Source: Internet
Author: User
Tags assert goto mutex

I. Background

In some CPU-intensive application scenarios, the processing of computational tasks is time-consuming (such as image processing), considering the advantages of multi-core CPU, if the calculation can be shared into multiple threads can be effectively utilized CPU;

However, if too many threads are turned on, the overhead of thread creation and destruction, and switching between threads, can not be underestimated; Ii. related Knowledge

2.1 Ideas Finishing

For this scenario, the design thread pool handles the task, that is, all pending tasks are concentrated in the queue, and N threads take turns to compute the queue;

2.2 Implementation of queues

Queue using a previous article to achieve the "chain queue", the queue data for the task of the callback function, task parameters;

The interface used is as follows:

Queue Request: Queue_alloc
Row operation: Queue_push
Column operation: Queue_pop
Queue destruction: Queue_free

2.2 Thread-related interface mutex initialization: Pthread_mutex_init (pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
Lock: Pthread_mutex_lock (pthread_mutex_t *mutex);
Unlock: Pthread_mutex_unlock (pthread_mutex_t *mutex);
Conditional variable initialization: pthread_cond_init (pthread_cond_t *cond,const pthread_cond_t *attr);
Thread hangs wait: pthread_cond_wait (pthread_cond_t *cond,pthread_mutex_t *mutex);
Wake single: Pthread_cond_signal (pthread_cond_t *cond);
All wakes: Pthread_cond_broadcast (pthread_cond_t *cond);

Third, realize

The definition of the structure, struct tpool is the management structure of the thread pool, struct routine for the task unit to be executed:

#define MAX_THREAD_NUM
#define MAX_TASKITEM 1024

typedef struct TPOOL
{
    U8 enable;
    
    queue_t *queue;
    
    pthread_attr_t attr;
    pthread_mutex_t Mutex;
    pthread_cond_t cond;
    pthread_t Tids[max_thread_num];
    
    U16 num;
} tpool_t;

struct routine {
    void *args;
    void (*callback) (void *);
Initialization of the thread pool, pre-boot max_thread_num child threads, each child thread ready to wait:

tpool_t *tpool_alloc (U16 num) {int ret = failure;
    
    int IX = 0;
    
    tpool_t *phead = NULL;
    if (num = = 0 | | | num > Max_thread_num) {goto _e1;
    } Phead = calloc (1, sizeof (tpool_t));
    if (!phead) {goto _e1; 
    } phead->enable = 1;
    Phead->num = num;
    Phead->queue = Queue_alloc (Max_taskitem);
    if (!phead->queue) {goto _e2;
    ret = Pthread_attr_init (&phead->attr);
    RET |= pthread_mutex_init (&phead->mutex, NULL);
    RET |= pthread_cond_init (&phead->cond, NULL);
    if (SUCCESS!= ret) {goto _e3;
    ret = Pthread_attr_setdetachstate (&phead->attr, pthread_create_detached);
    if (SUCCESS!= ret) {goto _e4; for (ix = 0; IX < num; ix++) {ret = Pthread_create (&phead->tids[ix], NULL, __worker, Phead
        );
        if (SUCCESS!= ret) {goto _e4; } REt = SUCCESS;
    
Goto _e1;
    _e4:pthread_mutex_destroy (&phead->mutex);
    Pthread_cond_destroy (&phead->cond);
Pthread_attr_destroy (&AMP;PHEAD-&GT;ATTR);
_e3:queue_free (&phead->queue, free);
_e2:free_pointer (Phead);
_e1:return Phead; }

The implementation of the child thread is as follows, one is suspend hibernate when the queue is empty, wake up to take the unit of work in the queue to call, until the queue empty again into hibernation;

Because queues are shared resources, it is necessary to use locks for protection under multithreading;

static int __worker_routine (tpool_t *phead) {struct routine *prt = NULL;
    Pthread_mutex_lock (&phead->mutex);
        if (Queue_isempty (phead->queue)) {printf ("Thread #%u Go sleep!\n", (U32) pthread_self ());
        Pthread_cond_wait (&phead->cond, &phead->mutex);
    printf ("Thread #%u wakeup!\n", (U32) pthread_self ());
    } prt = (struct routine *) Queue_pop (phead->queue);
    
    Pthread_mutex_unlock (&phead->mutex);
        if (PRT) {prt->callback (Prt->args);
    return SUCCESS;
return failure;
    
    } static void *__worker (void *args) {tpool_t *phead = (tpool_t *) args;
    if (!args) {return NULL; while (phead->enable) {if (SUCCESS!= __worker_routine (phead)) {printf ("__worker_r
            Outine return, Thread quit!\n ");
        Break
} return NULL; }


The above working child thread is the consumer, also needs the main thread to act as the producer, puts the work thread to the work task;

int Tpool_routine_add (tpool_t *phead, Void (*callback) (void *), void *args) {struct routine *prt
    = NULL;
    
    if (!phead | |!callback | |!args) {return
        failure;
    }
    
    PRT = (struct routine *) calloc (1, sizeof (struct routine));
    if (!prt) {return
        failure;
    }
    Prt->callback = callback;
    Prt->args = args;
    
    
    Pthread_mutex_lock (&phead->mutex);
    if (SUCCESS!= queue_push (Phead->queue, NULL, PRT)) {
        free_pointer (PRT);
        Pthread_mutex_unlock (&phead->mutex);
        return failure;
    }
    Pthread_cond_signal (&phead->cond);
    Pthread_mutex_unlock (&phead->mutex);
    return SUCCESS;
}

The destruction of the thread pool, which is to make the threads empty, then wait for all the child threads to exit, and then destroy the relevant members;

Note that the function is likely to block;

int tpool_destory (tpool_t *phead)
{
    int ix = 0;
    
    if (!phead) {return
        failure;
    }
    
    phead->enable = 0;
    
    Pthread_mutex_lock (&phead->mutex);
    Pthread_cond_broadcast (&phead->cond);
    Pthread_mutex_unlock (&phead->mutex);
    
    for (ix = 0; IX < phead->num; ix++) {
        pthread_join (Phead->tids[ix], NULL);
    
    Pthread_mutex_destroy (&phead->mutex);
    Pthread_cond_destroy (&phead->cond);
    Pthread_attr_destroy (&phead->attr);
    
    return SUCCESS;
}

Test function:

The working unit is the following, using hibernation 10 seconds to simulate time-consuming operations:

struct item {int value;};
    
    void Test_worker (void *args) {struct Item *pitem = (struct item *) args;
        if (!args) {printf ("null\n");
    Return
    printf ("Begin,%d\n", pitem->value);
    Sleep (10);
    
    printf ("End,%d\n", pitem->value);
Free (pitem); }
int main () {int ret = failure;
    
    struct Item *pitem = NULL;
    
    tpool_t *phead = NULL;
    
    Assert_fail (NULL, phead = Tpool_alloc (10));
    Sleep (2);
    printf ("1\n");
    Assert_fail (NULL, pitem = (struct item *) calloc (1, sizeof (struct item));
    Pitem->value = 1;
    
    ASSERT (SUCCESS, ret = Tpool_routine_add (Phead, Test_worker, Pitem));
    printf ("2\n");
    Assert_fail (NULL, pitem = (struct item *) calloc (1, sizeof (struct item));
    Pitem->value = 2;
    
    ASSERT (SUCCESS, ret = Tpool_routine_add (Phead, Test_worker, Pitem));
    printf ("3\n");
    Assert_fail (NULL, pitem = (struct item *) calloc (1, sizeof (struct item));
    Pitem->value = 3;
    ASSERT (SUCCESS, ret = Tpool_routine_add (Phead, Test_worker, Pitem));
    
    Sleep (2);
    printf ("close\n");
ASSERT (SUCCESS, ret = tpool_destory (phead)); _e1:printf ("Result:%s\n", ret?)
    "Failure": "SUCCESS"); return ret?
exit_failure:exit_success; }
Iv. Summary

The test results are as follows:

The result indicates that when the work child thread is doing task processing (SLEEP10 simulation), pushing the new work task does not interrupt the current task, but is awakened by other idle threads;

At the same time when the exit signal is issued, because the program to wait for the current task after the end of the exit, so there is a certain delay;


Reference articles:

[1] C language to implement a simple thread pool, http://www.cnblogs.com/newth/archive/2012/05/09/2492459.html

[2] Mutual exclusion lock and condition variable, http://www.cnblogs.com/zendu/p/4981480.html

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.