Linux网络编程——线程池模型
前言
线程池创建代码参考博客:https://blog.csdn.net/weixin_38956024/article/details/107892958
一、线程池主要函数说明
threadpool_t* threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size)
//创建一个线程池
//min_thr_num:线程池中最少存活的线程数量
//max_thr_num:线程池的最大容量
//queue_max_size:任务队列的最大数量
//返回值:指向一个线程池的指针。
int threadpool_add(threadpool_t *pool, void *(*function)(void *arg), void *arg)
//向线程池的任务队列中添加队列
//pool:指定的线程池
//func:函数指针,指向真正处理事务的函数
//arg:func的参数
//返回值:成功(0);失败(-1)
void *threadpool_thread(void *threadpool)
//任务线程调用的函数
void *adjust_thread(void *threadpool)
//管理线程使用的函数
int threadpool_destroy(threadpool_t *pool)
int threadpool_free(threadpool_t *pool)
//线程池的的销毁和释放函数
void *process(void *arg)
//真正完成任务的函数
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
二、代码实现
#include <iostream>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#define DEFAULT_TIME 10
#define MIN_WAIT_TASK_NUM 10
#define DEFAULT_THREAD_VARY 10
#define true 1
#define false 0
#define SERV_PORT 9999
using namespace std;
typedef struct
{
void *(*function)(void *);
void *arg; //the parameter of function
} threadpool_task_t;
//the struct of threadpool
struct threadpool_t
{
pthread_mutex_t lock; //the lock of threadpool_t
pthread_mutex_t thread_counter; //busy thread number
pthread_cond_t queue_not_full; //when the task queue is full, we need to wait it not full to add task thread
pthread_cond_t queue_not_empty; //when the task queue isn't empty, notice the waiting task thread
pthread_t *threads; //the array of thread's tid
pthread_t adjust_tid; //the administration thread's tid
threadpool_task_t *task_queue; // the array of task queue
int min_thr_num; //the min_thr_num in threadpool
int max_thr_num; //the max_thr_num in threadpool
int live_thr_num; //the live_thr_num in threadpool
int busy_thr_num; //the busy_thr_num in threadpool
int wait_exit_thr_num; //the number of thread who will be destory(exit)
int queue_front; //the task queue's head
int queue_rear; //the task queue's tail
int queue_size; //the task queue's current size
int queue_max_size; //the task queue's capacity
int shutdown; //flag: the using state of threadpool, its value is true(shutdown) or false(not shutdown)
};
void *threadpool_thread(void *threadpool);
void *adjust_thread(void *threadpool);
int is_thread_alive(pthread_t tid);
int threadpool_free(threadpool_t *pool);
threadpool_t* threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size)
{
threadpool_t *pool = NULL;
do
{
if((pool = new threadpool_t) == NULL)
{
cout << "new threadpool is fail" <<endl;
break;
}
pool->min_thr_num = min_thr_num;
pool->max_thr_num = max_thr_num;
pool->busy_thr_num = 0;
pool->live_thr_num = min_thr_num;
pool->wait_exit_thr_num = 0;
pool->queue_size = 0;
pool->queue_max_size = queue_max_size;
pool->queue_front = 0;
pool->queue_rear = 0;
pool->shutdown = false;
//malloc space for task thread
pool->threads = new pthread_t[max_thr_num];
if(pool->threads == NULL)
{
cout << "new pthread_t[max_thr_num] fail"<<endl;
break;
}
//malloc task queue space
pool->task_queue = new threadpool_task_t[queue_max_size];
if(pool->task_queue == NULL)
{
cout << "new task_queue fail"<<endl;
break;
}
if(pthread_mutex_init(&pool->lock,NULL) != 0
|| pthread_mutex_init(&pool->thread_counter,NULL) != 0
|| pthread_cond_init(&pool->queue_not_full,NULL) != 0
|| pthread_cond_init(&pool->queue_not_empty,NULL) != 0)
{
cout << "init the mutex or cond fail"<<endl;
break;
}
for(int i = 0; i <min_thr_num; i++)
{
pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void*)pool);
cout << "start thread " << (unsigned int)pool->threads[i]<<endl;
}
pthread_create(&(pool->adjust_tid), NULL, adjust_thread, (void *)pool);
return pool;
}while(0);
return NULL;
}
//add a task to threadpool
int threadpool_add(threadpool_t *pool, void *(*function)(void *arg), void *arg)
{
pthread_mutex_lock(&pool->lock);
while((pool->queue_size == pool->queue_max_size) && (!pool->shutdown))
{
pthread_cond_wait(&pool->queue_not_full, &pool->lock);
}
if(pool->shutdown)
{
pthread_cond_broadcast(&pool->queue_not_empty);
pthread_mutex_unlock(&pool->lock);
return 0;
}
if(pool->task_queue[pool->queue_rear].arg != NULL)
{
pool->task_queue[pool->queue_rear].arg = NULL;
}
pool->task_queue[pool->queue_rear].function =function;
pool->task_queue[pool->queue_rear].arg = arg;
pool->queue_rear = (pool->queue_rear + 1) % pool->queue_max_size;
pool->queue_size++;
pthread_cond_signal(&pool->queue_not_empty);
pthread_mutex_unlock(&pool->lock);
return 0;
}
//the working thread in threadpool
void *threadpool_thread(void *threadpool)
{
threadpool_t *pool = (threadpool_t *)threadpool;
threadpool_task_t task;
while(1)
{
pthread_mutex_lock(&pool->lock);
while((pool->queue_size == 0) && (!pool->shutdown))
{
cout<<"thread "<< (unsigned int)pthread_self() << "is waiting"<<endl;
pthread_cond_wait(&pool->queue_not_empty, &pool->lock);
if(pool->wait_exit_thr_num > 0)
{
pool->wait_exit_thr_num-- ;
if(pool->live_thr_num > pool->min_thr_num)
{
cout << "thread " << (unsigned int)pthread_self() << "is exiting...." <<endl;
pool->live_thr_num-- ;
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL);
}
}
}
if(pool->shutdown)
{
pthread_mutex_unlock(&pool->lock);
cout << "thread " <<(unsigned int)pthread_self() << "is exiting"<<endl;
pthread_detach(pthread_self());
pthread_exit(NULL);
}
task.function = pool->task_queue[pool->queue_front].function;
task.arg = pool->task_queue[pool->queue_front].arg;
pool->queue_front = (pool->queue_front +1) % pool->queue_max_size;
pool->queue_size--;
pthread_cond_broadcast(&pool->queue_not_full);
pthread_mutex_unlock(&pool->lock);
cout << "thread " << (unsigned int)pthread_self() << "is working!" <<endl;
pthread_mutex_lock(&pool->thread_counter);
pool->busy_thr_num++;
pthread_mutex_unlock(&pool->thread_counter);
(*(task.function))(task.arg);
cout << "thread " << (unsigned int)pthread_self() << "end working" <<endl;
pthread_mutex_lock(&pool->thread_counter);
pool->busy_thr_num --;
pthread_mutex_unlock(&pool->thread_counter);
}
pthread_exit(NULL);
}
//the administration's work thread function
void *adjust_thread(void *threadpool)
{
threadpool_t *pool = (threadpool_t *)threadpool;
while(!pool->shutdown)
{
sleep(DEFAULT_TIME);
pthread_mutex_lock(&pool->lock);
int queue_size = pool->queue_size;
int live_thr_num = pool->live_thr_num;
pthread_mutex_unlock(&pool->lock);
pthread_mutex_lock(&pool->thread_counter);
int busy_thr_num = pool->busy_thr_num;
pthread_mutex_unlock(&pool->thread_counter);
if(queue_size > MIN_WAIT_TASK_NUM && live_thr_num << pool->max_thr_num)
{
pthread_mutex_lock(&pool->lock);
int add = 0;
for(int i = 0; i < pool->max_thr_num && add < DEFAULT_THREAD_VARY &&pool->live_thr_num < pool->max_thr_num; i++)
{
if(pool->threads[i] == 0 || !is_thread_alive(pool->threads[i]) )
{
pthread_create(&pool->threads[i], NULL, threadpool_thread, (void*)pool);
add++;
pool->live_thr_num++;
}
}
pthread_mutex_unlock(&pool->lock);
}
if((busy_thr_num * 2) < pool->live_thr_num && live_thr_num > pool->min_thr_num)
{
pthread_mutex_lock(&pool->lock);
pool->wait_exit_thr_num = DEFAULT_THREAD_VARY;
pthread_mutex_unlock(&pool->lock);
for(int i = 0; i < DEFAULT_THREAD_VARY; i++)
{
pthread_cond_signal(&pool->queue_not_empty);
}
}
}
return NULL;
}
//destroy threadpool
int threadpool_destroy(threadpool_t *pool)
{
if(pool == NULL)
{
return -1;
}
pool->shutdown = true;
pthread_join(pool->adjust_tid, NULL);
for(int i = 0; i < pool->live_thr_num; i++)
{
pthread_cond_broadcast(&pool->queue_not_empty);
}
for(int i = 0; i < pool->live_thr_num; i++)
{
pthread_join(pool->threads[i], NULL);
}
threadpool_free(pool);
return 0;
}
//free threadpool
int threadpool_free(threadpool_t *pool)
{
if(pool == NULL) return -1;
if(pool->task_queue) delete pool->task_queue;
if(pool->threads)
{
delete pool->threads;
pthread_mutex_lock(&pool->lock);
pthread_mutex_destroy(&pool->lock);
pthread_mutex_lock(&pool->thread_counter);
pthread_mutex_destroy(&pool->thread_counter);
pthread_cond_destroy(&pool->queue_not_full);
pthread_cond_destroy(&pool->queue_not_empty);
}
delete pool;
pool = NULL;
return 0;
}
int threadpool_all_threadnum(threadpool_t *pool)
{
int all_threadnum = -1;
pthread_mutex_lock(&(pool->lock));
all_threadnum = pool->live_thr_num;
pthread_mutex_unlock(&(pool->lock));
return all_threadnum;
}
int threadpool_busy_threadnum(threadpool_t *pool)
{
int busy_threadnum = -1;
pthread_mutex_lock(&(pool->thread_counter));
busy_threadnum = pool->busy_thr_num;
pthread_mutex_unlock(&(pool->thread_counter));
return busy_threadnum;
}
//judge a thread is alive or not
int is_thread_alive(pthread_t tid)
{
int kill_rc = pthread_kill(tid, 0);
if(kill_rc == ESRCH)
{
return false;
}
return true;
}
void *process(void *arg)
{
//cout << "thread "<<pthread_self() << "working on task " << *((int *)arg) << endl;
//printf("thread 0x%x working on task %d\n ",(unsigned int)pthread_self(),(int)arg);
//sleep(1);
//printf("task %d is end\n",(int)arg);
//cout << "task " << *((int *)arg) << "is end!" <<endl;
//close(lfd);
int connfd = *((int*)arg);
cout << "In threead " << pthread_self() << ", connfd=" << connfd << endl;
int nread;
char buf[1024];
while(1)
{
nread = recv(connfd, buf, sizeof(buf), 0);
if(nread == -1)
{
perror("recv error");
close(connfd);
break;
}
else if (nread == 0)
{
cout << "------the have disconneted!------"<<endl;
close(connfd);
break;
}
else if(nread > 0)
{
for(int i = 0; i < nread; i++)
{
buf[i] = toupper(buf[i]);
}
send(connfd, buf, nread, 0);
}
}
return NULL;
}
int main(void)
{
/*threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size);*/
threadpool_t *thp = threadpool_create(3,100,100); /*创建线程池,池里最小3个线程,最大100,队列最大100*/
printf("pool inited");
// int num[20], i;
// for (i = 0; i < 20; i++) {
// num[i] = i;
// printf("add task %d\n",i);
// /*int threadpool_add(threadpool_t *pool, void*(*function)(void *arg), void *arg) */
// threadpool_add(thp, process, (void*)&num[i]); /* 向线程池中添加任务 */
// }
int lfd = socket(AF_INET,SOCK_STREAM, 0);
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(lfd, (sockaddr*)&serv_addr, sizeof(serv_addr));
if(ret == -1)
{
perror("bind error");
exit(1);
}
ret = listen(lfd, 256);
if(ret == -1)
{
perror("listen error");
exit(1);
}
int connfd;
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
while(1)
{
connfd = accept(lfd, (sockaddr*)&client_addr, &client_addr_len);
if(connfd == -1)
{
perror("accept error");
exit(1);
}
else
{
cout << "connfd="<<connfd<<endl;
threadpool_add(thp, process, (void*)&connfd);
}
}
//sleep(10); /* 等子线程完成任务 */
threadpool_destroy(thp);
return 0;
}