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;
}
運作結果如下:
建立的線程池存在的問題:
由于不知道有多少線程,是以初始化時容易建立過多的線程,造成資源浪費(解決方案:先設定一個門檻值,當超過這個門檻值就再建立一些線程;若不超過門檻值,就不用再建立線程)。