1.線程池說明
- 線程池擁有若干個線程
- 用於執行大量相對短暫的任務
由於線程個數小於任務的數量,因而任務需要進入隊列中進行等待,在短時間可以得到一個線程對任務進行處理
- 線程的個數與任務的類型有關
(1)計算密集型任務: 執行任務時很少被阻塞,線程個數=CPU個數(併發數是確定的),線程數過多,會導致線程上下文切換,降低效率
(2)I/O密集型任務: 執行任務時,可能會被I/O中斷,即線程被掛起,所以線程個數>CPU個數,若線程少了,剛好又都被掛起,當有新任務來了,無法處理任務了
- 當任務增加的時候能夠動態的增加線程池中線程的數量直到達到一個閾值
當任務執行完畢的時候,能夠動態的銷燬線程池中的線程
- 該線程池的實現本質上也是生產者與消費者模型的應用。
生產者線程向任務隊列中添加任務,一旦隊列有任務到來,如果有等待線程就喚醒來執行任務,如果沒有等待線程並且線程數沒有達到閾值,就創建新線程來執行任務。
2.線程池實現
- 測試驅動開發,先將數據結構寫好,再寫接口,然後make一下看是否報錯,最後再寫實現
typedef struct task
{
void *(*run)(void *arg);
void *arg;
struct task* next;
} task_t;
typedef struct threadpool
{
condition_t ready;
task_t *first;
task_t *last;
int counter;
int idle;
int max_threads;
int quit;
} threadpool_t;
void threadpool_init(threadpool_t *pool, int threads);
void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg);
void threadpool_destroy(threadpool_t *pool);
- eg:線程池的實現
NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\threadpool.h
NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\threadpool.c
========================NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\threadpool.h========
#ifndef NETWORKPROGRAMMING_THREADPOOL_H
#define NETWORKPROGRAMMING_THREADPOOL_H
#include "condition.h"
typedef struct task
{
void *(*run)(void *arg);
void *arg;
struct task* next;
} task_t;
typedef struct threadpool
{
condition_t ready;
task_t *first;
task_t *last;
int counter;
int idle;
int max_threads;
int quit;
} threadpool_t;
void threadpool_init(threadpool_t *pool, int threads);
void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg);
void threadpool_destroy(threadpool_t *pool);
#endif
======NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\threadpool.c==========
#include "threadpool.h"
#include <pthread.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
void *thread_routine (void *arg)
{
struct timespec abstime;
int timeout;
printf("thread 0x%x is starting\n", (int)pthread_self());
threadpool_t *pool = (threadpool_t*)arg;
while (1)
{
timeout = 0;
condition_lock(&pool->ready);
pool->idle++;
while (pool->first == NULL && !pool->quit)
{
printf("thread 0x%x is waiting\n", (int)pthread_self());
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += 2;
int state = condition_timewait(&pool->ready, &abstime);
if (state == ETIMEDOUT)
{
printf("thread 0x%x is wait time out\n", (int)pthread_self());
timeout = 1;
break;
}
}
pool->idle--;
if (pool->first != NULL)
{
task_t *t = pool->first;
pool->first = t->next;
condition_unlock(&pool->ready);
t->run(t->arg);
free(t);
condition_lock(&pool->ready);
}
if (pool->quit && pool->first == NULL)
{
pool->counter--;
if (pool->counter == 0)
{
condition_signal(&pool->ready);
}
condition_unlock(&pool->ready);
break;
}
if (timeout && pool->first == NULL)
{
pool->counter--;
condition_unlock(&pool->ready);
break;
}
condition_unlock(&pool->ready);
}
printf("thread 0x%x is exiting \n", (int)pthread_self());
return NULL;
}
void threadpool_init(threadpool_t *pool, int threads)
{
condition_init(&(pool->ready));
pool->first = NULL;
pool->last = NULL;
pool->counter = 0;
pool->idle = 0;
pool->max_threads = threads;
pool->quit = 0;
}
void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg)
{
void *(*run)(void *arg);
void *arg;
struct task* next;
task_t* newtask = (task_t *)malloc(sizeof(task_t));
newtask->run = run;
newtask->arg = arg;
newtask->next = NULL;
condition_lock(&pool->ready);
if (pool->first == NULL)
{
pool->first = newtask;
}
else
{
pool->last->next = newtask;
}
pool->last = newtask;
if (pool->idle > 0)
{
condition_signal(&pool->ready);
}
else if (pool->counter < pool->max_threads)
{
pthread_t tid;
pthread_create(&tid, NULL, thread_routine, pool);
++pool->counter;
}
condition_unlock(&pool->ready);
}
void threadpool_destroy(threadpool_t *pool)
{
if (pool->quit)
{
return;
}
condition_lock(&pool->ready);
pool->quit = 1;
if (pool->counter > 0)
{
if (pool->idle > 0)
{
condition_broadcast(&pool->ready);
}
while (pool->counter > 0)
{
condition_wait(&pool->ready);
}
}
condition_unlock(&pool->ready);
condition_destroy(&pool->ready);
}
- eg:線程池的條件變量和互斥量的封裝
NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\condition.h
NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\condition.c
===============NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\condition.h==================
#ifndef NETWORKPROGRAMMING_CONDITION_H
#define NETWORKPROGRAMMING_CONDITION_H
#include <pthread.h>
typedef struct condition
{
pthread_mutex_t pmutex;
pthread_cond_t pcond;
} condition_t;
int condition_init(condition_t *cond);
int condition_lock(condition_t *cond);
int condition_unlock(condition_t *cond);
int condition_wait(condition_t *cond);
int condition_timewait(condition_t *cond, const struct timespec *abstime);
int condition_signal(condition_t *cond);
int condition_broadcast(condition_t *cond);
int condition_destroy(condition_t *cond);
#endif
===================NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\condition.c====================
#include "condition.h"
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int condition_init(condition_t *cond)
{
int state;
state = pthread_cond_init(&(cond->pcond), NULL);
if (state == 0)
{
return state;
}
state = pthread_mutex_init(&(cond->pmutex), NULL);
if (state == 0)
{
return state;
}
return 0;
}
int condition_lock(condition_t *cond)
{
if (pthread_mutex_lock(&(cond->pmutex)) == 0)
{
printf("pthread_mutex_lock error\n");
exit(EXIT_FAILURE);
}
return 1;
}
int condition_unlock(condition_t *cond)
{
pthread_mutex_unlock(&(cond->pmutex));
}
int condition_wait(condition_t *cond)
{
return pthread_cond_wait(&(cond->pcond), &(cond->pmutex));
}
int condition_timewait(condition_t *cond, const struct timespec *abstime)
{
return pthread_cond_timedwait(&(cond->pcond), &(cond->pmutex), abstime);
}
int condition_signal(condition_t *cond)
{
return pthread_cond_signal(&(cond->pcond));
}
int condition_broadcast(condition_t *cond)
{
return pthread_cond_broadcast(&(cond->pcond));
}
int condition_destroy(condition_t *cond)
{
int state;
state = pthread_cond_destroy(&(cond->pcond));
if (state == 0)
{
return state;
}
state = pthread_mutex_destroy(&(cond->pmutex));
if (state == 0)
{
return state;
}
return 0;
}
- NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\test.c
#include "condition.h"
#include "threadpool.h"
#include <iostream>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
void *run (void *arg)
{
printf("threadpool 0x%x working task %d\n", (int)pthread_self(), *(int*)(arg));
sleep(1);
free(arg);
return NULL;
}
int main(void)
{
threadpool_t pool;
threadpool_init(&pool, 3);
int i;
for (i = 0; i < 10; ++i)
{
int *a = (int*)malloc(sizeof(int));
*a = i;
threadpool_add_task(&pool, run, a);
}
threadpool_destroy(&pool);
return 0;
}
- 測試結果:
若將下面的代碼屏蔽,程序則無法銷燬
if (pool->counter == 0)
{
condition_signal(&pool->ready);
}
.PHONY:clean
CC=gcc
CFLAGS=-Wall -g
ALL=main
OBJS=threadpool.o main.o condition.o
all:$(ALL)
%.o:%.c
$(cc) $(CFLAGS) -c $< -o $@
main:$(OBJS)
$(cc) $(CFLAGS) $^ -o $@ -lpthread -lrt
clean:
rm -f $(ALL) *.o