前言
最初一开始的时候,我们是采用一种一个任务一个线程(进程,其实在内核看来进程和线程都是一个东西)运行。
任务一做完,进程(线程)就要销毁,所有的空间都要收回。
但是很多时候,时间花在了销毁和创建进程。
我们仔细想想我们人在工作的时候,工作做完了,任务完成了,但是人没有消亡。
映射在这里是不是可以让进程(线程)不要关闭,等待任务的到来。
想法
既然我们想让进程不要消亡,那么就要解决掉如下问题:
1.接收、管理任务。
2.管理忙碌的线程,空闲的进程。
3.帮助相应的进程(线程)找到没有处理的任务。
4.监控线程,查看是不是出现了问题。(非必要)
解决方案
问题一:
首先我们需要在接收到任务的时候:
不是立即开始创建一个进程,而是将一个线程分配出去工作。
那么就会出现线程不够的问题,导致这个任务第一时间无法解决。
所以我们需要一种数据结构,保存一下任务请求。
我们需要选择一个比较好的数据结构,符合这个任务池需求和性质
1.遵循先来先服务原则,优先考虑队列
2.任务是大小不确定的、分高峰期和低谷期,优先考虑是链式结构。
3.任务一来通知其他的线程开始工作。(特殊性)
所以我们选择双向链式队列进行保存任务请求。
问题二:
首先我们需要多个线程,这些线程是永久性存在的。
同样我们需要选一种数据结构,保存下来这些线程
我们首先先分休闲线程池和忙碌线程池两种:
休闲线程池:
1.管理所有空闲线程
2.可以在任意的地方取出线程,放入忙碌线程
忙碌线程池:
1.管理所有的忙碌线程
2.每一个线程都有可能最先完成,需要频繁中间删除
忙碌线程池优先考虑双向链式顺序表,为了避免在写很多的代码,也可以考虑将休闲线程池做成和忙碌线程池一样的
问题三:
关于任务组装的问题:
我们可以考虑使用函数指针方法进行组装。
#include "pool.h"
PTHREAD_QUEUE * pthread_leisure_queue;
PTHREAD_QUEUE * pthread_busy_queue;
TASK_QUEUE * task_NeedWork_queue;
void sys_clean(void)
{
perror("system error");
exit(EXIT_FAILURE);
}
void * Pthread_Work(void * ptr)
{
PTHREAD_NODE * self = (PTHREAD_NODE *) ptr;
pthread_mutex_lock (&self->mutex);
self->tid = syscall (SYS_gettid);
pthread_mutex_unlock (&self->mutex);
while (1)
{
pthread_mutex_lock (&self->mutex);
if(self->work==NULL)
pthread_cond_wait(&self->cond,&self->mutex);
pthread_mutex_lock (&self->work->mutex);
self->work->fun(self->work->arg);
self->work->fun = NULL;
free(self->work->arg);
self->work->flag = 0;
self->next = NULL;
self->tid = 0;
self->work->arg=NULL;
pthread_mutex_unlock (&self->work->mutex);
free (self->work);
self->work = NULL;
pthread_mutex_lock(&pthread_busy_queue->mutex);
if(pthread_busy_queue->size==1)
{
pthread_busy_queue->rear = NULL;
pthread_busy_queue->head = NULL;
}
else if(pthread_busy_queue->rear==self&&pthread_busy_queue->head!=self)
{
pthread_busy_queue->rear = self->prev;
pthread_busy_queue->rear->next = NULL;
}
else if(pthread_busy_queue->head == self && pthread_busy_queue->rear != self)
{
pthread_busy_queue->head = self->next;
self->next->prev = NULL;
}
else
{
self->prev ->next = self->next;
self->next->prev = self->prev;
}
self->prev = self->next = NULL;
pthread_busy_queue->size--;
pthread_mutex_unlock(&pthread_busy_queue->mutex);
pthread_mutex_lock(&pthread_leisure_queue->mutex);
if(pthread_leisure_queue->size==0)
{
pthread_leisure_queue->head = self ;
pthread_leisure_queue->rear = self;
}
else
{
pthread_leisure_queue->rear ->next = self;
pthread_leisure_queue->rear = self;
}
pthread_leisure_queue->size++;
pthread_mutex_unlock(&pthread_leisure_queue->mutex);
pthread_mutex_unlock(&self->mutex);
pthread_cond_signal(&pthread_leisure_queue->cond);
}
}
void Create_Pthread_Node()
{
pthread_mutex_lock (&pthread_leisure_queue->mutex);
PTHREAD_NODE * temp = NULL;
PTHREAD_NODE * preTmp = NULL;
for(int i = 1;i<=PTHREAD_DEF_NUMBER;i++)
{
temp = (PTHREAD_NODE *) malloc(sizeof(PTHREAD_NODE));
if(temp == NULL)
{
printf ("malloc failure\n");
exit (EXIT_FAILURE);
}
if(i==1)
pthread_leisure_queue->head = temp;
temp->flag = 0;
temp->prev = preTmp;
temp->work = NULL;
pthread_cond_init(&(temp->cond),NULL);
pthread_mutex_init(&(temp->mutex),NULL);
temp->prev = preTmp;
if(preTmp!=NULL)
preTmp->next = temp;
pthread_create(&temp->tid,NULL,Pthread_Work,(void *)temp);
preTmp = temp;
temp = NULL;
}
pthread_leisure_queue->rear = preTmp;
pthread_leisure_queue->size = PTHREAD_DEF_NUMBER;
pthread_mutex_unlock(&(pthread_leisure_queue->mutex));
}
void PthreadPool_system_init()
{
pthread_leisure_queue = (PTHREAD_QUEUE *)malloc(sizeof(PTHREAD_QUEUE));
pthread_leisure_queue->head = NULL;
pthread_leisure_queue->rear = NULL;
pthread_leisure_queue->size = 0;
pthread_cond_init(&(pthread_leisure_queue->cond),NULL);
pthread_mutex_init(&(pthread_leisure_queue->mutex),NULL);
pthread_busy_queue = (PTHREAD_QUEUE *)malloc(sizeof(PTHREAD_QUEUE));
pthread_busy_queue->size = 0;
pthread_busy_queue->rear = NULL;
pthread_busy_queue->head = NULL;
pthread_cond_init(&(pthread_busy_queue->cond),NULL);
pthread_mutex_init(&(pthread_busy_queue->mutex),NULL);
task_NeedWork_queue = (TASK_QUEUE * )malloc(sizeof(TASK_QUEUE));
task_NeedWork_queue->size = 0;
task_NeedWork_queue->head = NULL;
task_NeedWork_queue->rear = NULL;
pthread_cond_init(&(task_NeedWork_queue->cond),NULL);
pthread_mutex_init(&(task_NeedWork_queue->mutex),NULL);
Create_Pthread_Node();
}
void *prcoess_client(void * ptr)
{
int net_fd;
net_fd = atoi((char *)ptr);
char buff[128];
if(-1 == recv (net_fd, buff, sizeof (buff), 0))
{
printf ("recv msg error\n");
close (net_fd);
goto clean;
}
printf("%d\n",syscall (SYS_gettid));
strcpy(buff,"hello i'm server");
if(-1==send(net_fd,buff,strlen(buff),0))
{
printf ("send msg error\n");
close (net_fd);
goto clean;
}
close (net_fd);
return;
clean:
sys_clean();
}
void Task_Manager()
{
int sock_fd;
sock_fd = socket(AF_INET,SOCK_STREAM,0);
if(sock_fd==-1)
{
perror("listen error");
goto clean;
}
struct sockaddr_in myaddrs;
memset(&myaddrs,0,sizeof(myaddrs));
myaddrs.sin_port = htons(POST);
myaddrs.sin_family = AF_INET;
myaddrs.sin_addr.s_addr = INADDR_ANY;
if(-1==(bind(sock_fd,(struct sockaddr *)&myaddrs,sizeof(myaddrs))))
{
perror("bind");
goto clean;
}
if (-1 == listen (sock_fd, 5))
{
perror ("listen");
goto clean;
}
TASK_NODE * newtask;
for(int number = 1;;number++)
{
int newfd;
struct sockaddr_in client;
socklen_t len = sizeof (client);
if (-1 ==(newfd = accept (sock_fd, (struct sockaddr *) &client, &len)))
{
perror ("accept");
goto clean;
}
newtask = (TASK_NODE *) malloc (sizeof (TASK_NODE));
if (newtask == NULL)
{
printf ("malloc error");
goto clean;
}
newtask->flag = 0;
newtask->arg = (void *) malloc (128);
memset (newtask->arg, '\0', 128);
sprintf (newtask->arg, "%d", newfd);
newtask->next = NULL;
newtask->fun = prcoess_client;
newtask->tid = 0;
newtask->work_id = number;
pthread_mutex_init(&(newtask->mutex),NULL);
pthread_mutex_lock(&(task_NeedWork_queue->mutex));
if(task_NeedWork_queue->size == 0)
{
task_NeedWork_queue->head = newtask;
task_NeedWork_queue->rear = newtask;
}
else
{
task_NeedWork_queue->rear->next = newtask;
task_NeedWork_queue->rear = newtask;
}
task_NeedWork_queue->size++;
pthread_mutex_unlock(&(task_NeedWork_queue->mutex));
pthread_cond_signal(&(task_NeedWork_queue->cond));
}
return;
clean:
sys_clean();
}
void Thread_Manager()
{
PTHREAD_NODE * temp_thread;
TASK_NODE * temp_task;
while(1)
{
temp_thread = NULL;
temp_task = NULL;
pthread_mutex_lock(&(task_NeedWork_queue->mutex));
if(task_NeedWork_queue->size==0)
pthread_cond_wait(&(task_NeedWork_queue->cond),&(task_NeedWork_queue->mutex));
task_NeedWork_queue->size--;
temp_task = task_NeedWork_queue->head;
task_NeedWork_queue->head = task_NeedWork_queue->head->next;
temp_task->next = NULL;
pthread_mutex_unlock(&(task_NeedWork_queue->mutex));
pthread_mutex_lock(&(pthread_leisure_queue->mutex));
if(pthread_leisure_queue->size==0)
pthread_cond_wait(&(pthread_leisure_queue->cond),&(pthread_leisure_queue->mutex));
temp_thread = pthread_leisure_queue->head;
if(pthread_leisure_queue->head==pthread_leisure_queue->rear)
{
pthread_leisure_queue->head = NULL;
pthread_leisure_queue->rear = NULL;
}
else
{
pthread_leisure_queue->head = pthread_leisure_queue->head->next;
pthread_leisure_queue->head->prev = NULL;
}
pthread_leisure_queue->size--;
pthread_mutex_unlock(&(pthread_leisure_queue->mutex));
pthread_mutex_lock(&(temp_thread->mutex));
temp_thread->flag = 1;
temp_thread->next = NULL;
temp_thread->prev =NULL;
temp_thread->work = temp_task;
pthread_mutex_unlock(&(temp_thread->mutex));
pthread_mutex_lock(&(pthread_busy_queue->mutex));
if(pthread_busy_queue->size==0)
{
pthread_busy_queue->rear = temp_thread;
pthread_busy_queue->head = temp_thread;
}
else
{
pthread_busy_queue->rear->next = temp_thread;
temp_thread->prev = pthread_busy_queue->rear;
pthread_busy_queue->rear = temp_thread;
}
pthread_busy_queue->size++;
pthread_mutex_unlock(&(pthread_busy_queue->mutex));
pthread_cond_signal(&(temp_thread->cond));
}
}
void monitor(void * ptr)
{
int number = 1;
while (1)
{
printf("--------------------------------------------\n");
printf("检测数:%d\n",number);
pthread_mutex_lock(&(pthread_busy_queue->mutex));
printf("忙碌线程:%d\n",pthread_busy_queue->size);
pthread_mutex_unlock(&(pthread_busy_queue->mutex));
pthread_mutex_lock(&(pthread_leisure_queue->mutex));
printf("空闲线程:%d\n",pthread_leisure_queue->size);
pthread_mutex_unlock(&(pthread_leisure_queue->mutex));
pthread_mutex_lock(&(task_NeedWork_queue->mutex));
printf("任务数还有:%d\n",task_NeedWork_queue->size);
pthread_mutex_unlock(&(task_NeedWork_queue->mutex));
printf("--------------------------------------------\n\n\n");
number++;
sleep(1);
}
return;
}
#include"pool.h"
int main()
{
pthread_t thread_manager_tid, task_manager_tid,monitor_tid;
PthreadPool_system_init();
pthread_create(&task_manager_tid,NULL,Task_Manager,NULL);
pthread_create(&thread_manager_tid,NULL,Thread_Manager,NULL);
pthread_create(&monitor_tid,NULL,monitor,NULL);
pthread_join (thread_manager_tid, NULL);
pthread_join (task_manager_tid, NULL);
pthread_join(monitor_tid,NULL);
sys_clean ();
return 0;
}
#ifndef _MyPthread_pool_
#define _MyPthread_pool_
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <sys/stat.h>
#include <net/if_arp.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#define POST 9005
#define PTHREAD_MAX_NUMBER 50
#define PTHREAD_MIN_NUMBER 5
#define PTHREAD_DEF_NUMBER 20
typedef struct task_node
{
pthread_t tid;
//pthread_cond_t cond;
pthread_mutex_t mutex;
int flag; //1:busy,2:free
int work_id;
struct task_node * next;
void * (*fun)(void *);
void * arg;
}TASK_NODE;
typedef struct task_queue
{
pthread_mutex_t mutex;
pthread_cond_t cond;
struct task_node * head;
struct task_node * rear;
int size;
}TASK_QUEUE;
typedef struct pthread_node
{
pthread_t tid;
pthread_cond_t cond;
pthread_mutex_t mutex;
struct pthread_node * prev;
struct pthread_node * next;
int flag;
struct task_node * work;
}PTHREAD_NODE;
typedef struct pthread_queue
{
struct pthread_node * head;
struct pthread_node * rear;
pthread_mutex_t mutex;
pthread_cond_t cond;
int size;
}PTHREAD_QUEUE;
extern PTHREAD_QUEUE * pthread_leisure_queue;
extern PTHREAD_QUEUE * pthread_busy_queue;
extern TASK_QUEUE * task_NeedWork_queue;
void sys_clean(void);
void * Pthread_Work(void * ptr);
void Create_Pthread_Node();
void PthreadPool_system_init();
void *prcoess_client(void * ptr);
void Task_Manager();
void Thread_Manager();
void monitor(void * ptr);
#endif