天天看點

嵌入式技術筆記(十八):線程池

1. 多線程存在的問題

1、程序所支援的線程數量問題(受限)

2、線程的建立和銷毀的開銷問題

2. 線程池的概念

嵌入式技術筆記(十八):線程池

3. 建立線程池

要求:建立一個線程池和任務隊列, 往任務隊列中添加任務,線程池中線程的工作任務是輸出"hello world!"、"welcome to China!"和一個傳入的參數

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>


struct job
{
    void *((*func)(void *arg));
    void *arg;
    struct job *next;
};

struct threadpool
{
    int thread_num; 
    pthread_t *pthread_ids;
    struct job *head; //任務隊列的頭
    struct job *tail; //任務隊列的尾
    int queue_max_num;
    int queue_cur_num;

    pthread_mutex_t mutex;
    pthread_cond_t queue_empty;
    pthread_cond_t queue_not_empty;
    pthread_cond_t queue_not_full;
};

void *threadpool_function(void *arg)
{
    struct threadpool *pool = (struct threadpool *)arg;
    struct job *pjob = NULL;

    while(1)
    {
        pthread_mutex_lock(&(pool->mutex));

        while(pool->queue_cur_num == 0)
        {
            pthread_cond_wait(&(pool->queue_not_empty), &(pool->mutex));
        }

        pjob = pool->head;
        pool->queue_cur_num--;
        if(pool->queue_cur_num != pool->queue_max_num)
        {
            pthread_cond_broadcast(&(pool->queue_not_empty)); //喚醒條件變量
        }
        if(pool->queue_cur_num == 0)
        {
            pool->head = pool->tail = NULL;
        }
        else
        {
            pool->head = pool->head->next;
        }
        
        pthread_mutex_unlock(&(pool->mutex));
        
        (*(pjob->func))(pjob->arg);
        free(pjob);
        pjob = NULL;
          
    }
}

//線程池初始化函數
struct threadpool *threadpool_init(int thread_num, int queue_max_num)
{
    struct threadpool *pool = (struct threadpool *)malloc(sizeof(struct threadpool));
    //malloc

    pool->queue_max_num = queue_max_num;
    pool->queue_cur_num = 0;
    pool->head = NULL;
    pool->tail = NULL;

    pthread_mutex_init(&(pool->mutex), NULL);
    pthread_cond_init(&(pool->queue_empty), NULL);
    pthread_cond_init(&(pool->queue_not_empty), NULL);
    pthread_cond_init(&(pool->queue_not_full), NULL);

    pool->thread_num = thread_num;
    pool->pthread_ids = (pthread_t *)malloc(sizeof(pthread_t) *thread_num);
    //malloc

    for (int i = 0; i < pool->thread_num; i++)
    {
        pthread_create(&(pool->pthread_ids[i]), NULL, threadpool_function, (void *)pool);
    }

    return pool;
}

//往任務隊列裡添加任務的函數
void threadpool_add_job(struct threadpool *pool, void *(func)(void *), void *arg) 
{
    pthread_mutex_lock(&(pool->mutex));
    //判斷線程池是否為滿
    while(pool->queue_cur_num == pool->queue_max_num) 
    {
        pthread_cond_wait((&pool->queue_not_full), &(pool->mutex)); //阻塞等待
    }

    struct job *pjob = (struct job *)malloc(sizeof(struct job));
    //malloc
    //任務隊列參數初始化
    pjob->func = func;
    pjob->arg = arg;
    pjob->next = NULL;

    if(NULL == pool->head)
    {
        pool->head = pool->tail = pjob;
        pthread_cond_broadcast(&(pool->queue_not_empty)); 
    }
    else
    {
        pool->tail->next = pjob;
        pool->tail = pjob;
    }
    
    pool->queue_cur_num++;
    printf("%d\n", pool->queue_cur_num);
    pthread_mutex_unlock(&(pool->mutex));
}

void thread_destory(struct threadpool *pool)
{   
    pthread_mutex_lock(&(pool->mutex));
    while(pool->queue_cur_num != 0)
    {
        pthread_cond_wait(&(pool->queue_empty), &(pool->mutex));
    }
    pthread_mutex_unlock(&(pool->mutex));
    pthread_cond_broadcast(&(pool->queue_empty));
    pthread_cond_broadcast(&(pool->queue_not_empty));
    pthread_cond_broadcast(&(pool->queue_not_full));

    free(pool->pthread_ids); //釋放存放線程号的空間
    
    for (int i = 0; i < pool->thread_num; i++)
    {
        pthread_cancel(pool->pthread_ids[i]);
        pthread_join(pool->pthread_ids[i], NULL);
    }
    //釋放任務隊列
    struct job *temp;
    while(pool->head != NULL)
    {
        temp = pool->head;
        pool->head = temp->next;
        free(temp);
    }

    free(pool); //釋放線程池
}

//任務的工作函數
void *work(void *arg)
{
    char *p = (char *)arg;
    printf("hello world!  %s\n", p);
    printf("welcome to China!  %s\n", p);
    sleep(1);
}

int main()
{
    struct threadpool *pool = threadpool_init(10, 100); //線程池初始化
    threadpool_add_job(pool, work, "1");
    threadpool_add_job(pool, work, "2");
    threadpool_add_job(pool, work, "3");
    threadpool_add_job(pool, work, "4");
    threadpool_add_job(pool, work, "5");
    threadpool_add_job(pool, work, "6");
    threadpool_add_job(pool, work, "7");
    threadpool_add_job(pool, work, "8");
    threadpool_add_job(pool, work, "9");
    threadpool_add_job(pool, work, "10");

    return 0;
}

           

運作結果如下:

嵌入式技術筆記(十八):線程池

建立的線程池存在的問題:

由于不知道有多少線程,是以初始化時容易建立過多的線程,造成資源浪費(解決方案:先設定一個門檻值,當超過這個門檻值就再建立一些線程;若不超過門檻值,就不用再建立線程)。