epoll_pool_test

实现流程

  1. 网络初始化,创建服务器socket,绑定服务器地址,返回服务器sock

  2. epoll监听树初始化,创建监听树,监听服务器socket,返回监听树fd

  3. pool初始化,pool创建存储空间,pool扩容/缩容参数初始化,pool任务tid数组创建存储空间,pool条件变量初始化,pool任务队列创建存储空间,相关参数初始化,循环创建最小数量任务。创建管理任务,创建打印任务;返回pool指针

  4. epoll监听,如果线程池没有关闭循环监听,处理返回的就绪socket,如果是服务器sock,task添加为accept;如果不是,task添加为recv,处理完毕调用 producer将任务添加到线程执行。循环结束回收服务器sock

  5. 生产者添加任务,如果线程池在运行,检测。如果当前任务等一最大任务,队列满,生产者等待,如果线程池关闭,解锁。队伍不满,给队列头指针添加任务,头指针后移1,当前指针++,pthread_kill发送SIGUSR1打印消息,通知消费者唤醒,解锁。

  6. 消费者分离线程,取线程池参数,线程池没有关闭循环获取任务执行。加锁,如果cur不为0(不为空),唤醒消费者。如果线程池关闭,解锁退出。如果需要销毁当前线程,活跃数量-1,销毁数量-1,从线程tid数组中移除当前线程,释放锁,退出当前线程,发送SIGUSR1信号。

    获取队列尾任务,队列尾+1,busy+1,唤醒生产者,解锁。执行任务,加锁,busy-1,发送SIGUSR1信号,解锁。

    如果线程池关闭返回NULL

  7. recv接收任务,取出参数客户sock,使用用户sock接收数据。如果接收成功,检查是否是time,是取时间,发送时间buf,不是时间,发送提示信息,清空接收buf,时间buf。如果接收失败,客户端退出,取消监听,关闭客户端sock,打印消息。

  8. accept任务,取出服务器sock,接收连接,如果成功,添加监听,打印客户端连接ip

  9. manager任务,线程分离,取出pool*。线程池没有关闭的时候,上锁,取出线程忙闲,大小,当前指针参数,解锁。如果当前数量>可用||忙占比>70%&&max>live+min,扩容min,循环如果tids数组不为空,循环添加min数量thread,live++,解锁。

    如果现存>2倍忙&&现有-min>=min,缩容。加锁,exit+10,解锁,循环挂起消费者

    如果线程池关闭,返回NULL

  10. 线程销毁,取出pool参数,销毁条件变量,销毁锁,释放队列,释放tids,释放pool

  11. 设置信号,备份信号。信号设为空,添加信号,设置屏蔽码并备份。

    初始化网络,初始化epoll,初始化pool,开始epoll监听

    如果线程池关闭,销毁线程。

  12. 打印线程池信息

  13. 打印线程。分离线程,取出pool参数。设置信号行为,设为空,处理函数设置为打印函数,参数设置为0。绑定信号SIGUSR1与信号行为,备份。设置信号屏蔽信息。

    如果线程池没有关闭,休眠1s。如果关闭,线程退出。

pool.h

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <signal.h>
#include <sys/epoll.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

typedef struct
{
	void* arg;
	void* (*busines)(void*);
}bs_t;

typedef struct
{
	int thread_shutdown;
	int thread_alive;
	int thread_busy;
	int thread_max;
	int thread_min;
	int thread_killnum;

	bs_t* queue;
	int front;
	int rear;
	int qmax;
	int cur;

	pthread_t *ctids;
	pthread_t mid;

	pthread_cond_t notEmpty;
	pthread_cond_t notFull;
}pool_t;

int epfd;
pthread_t ptid;
pthread_mutex_t lock;
pool_t* ptr;

int net_init(char* ip,int port);
int epoll_init(int sockfd,int listen_num);
void epoll_listen(int sockfd,pool_t* pt);
void producer_add(pool_t* pt,bs_t tmp);

pool_t* pool_init(int tmax,int tmin,int qmax);
void* manager(void* arg);
void* customer(void* arg);
void* recv_busines(void* arg);
void* accept_busines(void* arg);
void sig_usr(int n);
void* thread_printf(void* arg);
void thread_destroy(void* arg);

accept_task

#include <pool.h>

void* accept_busines(void* arg)
{
	int sockfd=*(int*)arg;
	int clientsock;
	struct sockaddr_in clientaddr;
	socklen_t len=sizeof(clientaddr);
	if((clientsock=accept(sockfd,(struct sockaddr*)&clientaddr,&len))==-1)
	{
		perror("accept_busines accept failed");
		exit(0);
	}
	char ip[16];
	char response[1024];
	bzero(response,1024);
	bzero(ip,16);
	struct epoll_event node;
	node.data.fd=clientsock;
	node.events=EPOLLIN|EPOLLET;
	if((epoll_ctl(epfd,EPOLL_CTL_ADD,clientsock,&node))!=0)
	{
		perror("accept_busines epoll_ctl failed");
		exit(0);
	}
	sprintf(response,"connection successful\n");
	inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,ip,16);
	send(clientsock,response,strlen(response),MSG_NOSIGNAL);
	return NULL;
}

recv_task

#include <pool.h>

void *recv_busines(void* arg)
{
	int sockfd=*(int*)arg;
	ssize_t recvNum;
	char recvBuf[1024];
	char ctime[1024];
	time_t tp;
	char* msg="tryagain\n";
	if((recvNum=recv(sockfd,recvBuf,sizeof(recvBuf),MSG_DONTWAIT))>0)
	{
		if((strcmp(recvBuf,"time\n"))==0)
		{
			tp=time(NULL);
			ctime_r(&tp,ctime);
			send(sockfd,ctime,strlen(ctime),MSG_NOSIGNAL);
		}
		else
		{
			send(sockfd,msg,strlen(msg),MSG_NOSIGNAL);
		}
		sleep(10);
		bzero(ctime,sizeof(ctime));
		bzero(recvBuf,sizeof(recvBuf));
	}
	else if(recvNum==0)
	{
		
		if((epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL))==-1)
		{
			perror("recv_busines epoll_ctl del failed");
			exit(0);
		}
		close(sockfd);
		printf("client exit...\n");
	}
}

net_init

#include <pool.h>

int net_init(char* ip,int port)
{
	int sockfd;
	if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
		perror("net_init socket failed");
		return -1;
	}
	struct sockaddr_in addr;
	addr.sin_family=AF_INET;
	addr.sin_port=htons(port);
	addr.sin_addr.s_addr=htonl(INADDR_ANY);
	if((bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)))==-1)
	{
		perror("net_init bind failed");
		return -1;
	}
	listen(sockfd,128);
	return sockfd;
}

pool_init

#include <pool.h>

pool_t* pool_init(int tmax,int tmin,int qmax)
{
	pool_t* pt;
	if((pt=(pool_t*)malloc(sizeof(pool_t)))==NULL)
	{
		printf("pool_init pool_t malloc failed\n");
		return NULL;
	}
	pt->thread_shutdown=1;
	pt->thread_alive=0;
	pt->thread_busy=0;
	pt->thread_max=tmax;
	pt->thread_min=tmin;
	pt->thread_killnum=0;
	if((pt->queue=(bs_t*)malloc(sizeof(bs_t)*qmax))==NULL)
	{
		printf("pool_init bs_t* malloc failed\n");
		return NULL;
	}
	pt->front=0;
	pt->rear=0;
	pt->qmax=qmax;
	pt->cur=0;
	if((pthread_cond_init(&pt->notEmpty,NULL)!=0)||(pthread_cond_init(&pt->notFull,NULL)!=0)||(pthread_mutex_init(&lock,NULL)!=0))
	{
		printf("pool_init cond or mutex init failed\n");
		return NULL;
	}
	if((pt->ctids=(pthread_t*)malloc(sizeof(pthread_t)*tmax))==NULL)
	{
		printf("pool_init ctids malloc failed\n");
		return NULL;
	}
	bzero(pt->ctids,sizeof(pthread_t)*tmax);
	//yuchuangjian 
	int err;
	for(int i=0;i<tmin;i++)
	{
		if((err=pthread_create(&pt->ctids[i],NULL,customer,(void*)pt))>0)
		{
			printf("pool_init pthread_create customer failed: %s\n",strerror(err));
			return NULL;
		}
		++pt->thread_alive;
	}
	if((err=pthread_create(&pt->mid,NULL,manager,(void*)pt))>0)
	{
		printf("pool_init pthead_create manager failed: %s\n",strerror(err));
		return NULL;
	}
	if((err=pthread_create(&ptid,NULL,thread_printf,(void*)pt))>0)
	{
		printf("pool_init pthread_create thread_printf failed: %s\n",strerror(err));
		return NULL;
	}
	return pt;
}

producer

#include <pool.h>

void producer_add(pool_t* pt,bs_t tmp)
{
	if(pt->thread_shutdown)
	{
		pthread_mutex_lock(&lock);
		while(pt->cur==pt->qmax)
		{
			pthread_cond_wait(&pt->notFull,&lock);
			if(!pt->thread_shutdown)
			{
				pthread_mutex_unlock(&lock);
				printf("producer shut %d,exit...\n",pt->thread_shutdown);
				exit(0);
			}
		}
		pt->queue[pt->front].arg=tmp.arg;
		pt->queue[pt->front].busines=tmp.busines;
		pt->front=(pt->front+1)%pt->qmax;
		++pt->cur;
		pthread_kill(ptid,SIGUSR1);
		pthread_mutex_unlock(&lock);
		pthread_cond_signal(&pt->notEmpty);
	}
}

comsumer

#include <pool.h>

void* customer(void* arg)
{
	pthread_detach(pthread_self());
	pool_t* pt=(pool_t*)arg;
	
	while(pt->thread_shutdown)
	{
		pthread_mutex_lock(&lock);
		while(pt->cur==0)
		{
			pthread_cond_wait(&pt->notEmpty,&lock);
			if(!pt->thread_shutdown)
			{
				printf("customer shutdown %d failed\n",pt->thread_shutdown);
				pthread_mutex_unlock(&lock);
				exit(0);
			}
			if(pt->thread_killnum)
			{
				--pt->thread_alive;
				--pt->thread_killnum;
				int n=pthread_self();
				for(int i=0;i<pt->thread_max;i++)
				{
					if(pt->ctids[i]==n)
					{
						pt->ctids[i]=0;
						break;
					}
				}
				pthread_mutex_unlock(&lock);
				pthread_exit(NULL);
				pthread_kill(ptid,SIGUSR1);
			}
		}
		bs_t tmp;
		//huoqurenwu
		tmp.arg=pt->queue[pt->rear].arg;
		tmp.busines=pt->queue[pt->rear].busines;
		pt->rear=(pt->rear+1)%pt->qmax;
		--pt->cur;
		++pt->thread_busy;
		pthread_kill(ptid,SIGUSR1);
		pthread_mutex_unlock(&lock);
		pthread_cond_signal(&pt->notFull);
		//zhixingrenwu
		tmp.busines(tmp.arg);
		pthread_mutex_lock(&lock);
		--pt->thread_busy;
		pthread_kill(ptid,SIGUSR1);
		pthread_mutex_unlock(&lock);
	}
	return NULL;
}

manager

#include <pool.h>

void* manager(void* arg)
{
	pthread_detach(pthread_self());
	pool_t* pt=(pool_t*)arg;
	int alive,busy,cur,tmax,tmin;
	while(pt->thread_shutdown)
	{
		pthread_mutex_lock(&lock);
		alive=pt->thread_alive;
		busy=pt->thread_busy;
		cur=pt->cur;
		tmax=pt->thread_max;
		tmin=pt->thread_min;
		pthread_mutex_unlock(&lock);
		int flag,add;
		//kuorong
		int err;
		if((cur>=alive-busy||(double)busy/alive*100>=70)&&alive+tmin<=tmax)
		{
			for(flag=0,add=0;flag<tmax&&add<tmin;flag++)
			{
				if(pt->ctids[flag]==0)
				{
					pthread_mutex_lock(&lock);
					if((err=pthread_create(&pt->ctids[flag],NULL,customer,(void*)pt))>0)
					{
						printf("manager pthread_create failed: %s\n",strerror(err));
						pthread_mutex_unlock(&lock);
					}					
					++pt->thread_alive;
					pthread_mutex_unlock(&lock);
					++add;
				}
			}
		}

		//suojian
		if(alive-busy>=2*busy && alive-tmin>=tmin)
		{
			pthread_mutex_lock(&lock);
			pt->thread_killnum=pt->thread_min;
			pthread_mutex_unlock(&lock);
			for(int i=0;i<tmin;i++)
			{
				pthread_cond_signal(&pt->notEmpty);
			}
		}
	}
	return NULL;
}

epoll_init

#include <pool.h>

int epoll_init(int sockfd,int listen_num)
{
	if((epfd=epoll_create(listen_num))==-1)
	{
		perror("epoll_init epoll_create failed");
		return -1;
	}
	struct epoll_event node;
	node.data.fd=sockfd;
	node.events=EPOLLIN|EPOLLET;
	if((epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&node))==-1)
	{
		perror("epoll_init epoll_ctl failed");
		return -1;
	}
	return 0;
}

epoll_listen

#include <pool.h>

void epoll_listen(int sockfd,pool_t *pt)
{
	int readyNum;
	struct epoll_event readyArray[100000];
	int flag;
	bs_t tmp;
	while(pt->thread_shutdown)
	{
		if((readyNum=epoll_wait(epfd,readyArray,100000,-1))==-1)
		{
			perror("epoll_listen epoll_wait failed");
			exit(0);
		}
		flag=0;
		while(readyNum)
		{
			if(readyArray[flag].data.fd==sockfd)
			{
				tmp.arg=(void*)&readyArray[flag].data.fd;
				tmp.busines=accept_busines;
			}
			else
			{
				tmp.arg=(void*)&readyArray[flag].data.fd;
				tmp.busines=recv_busines;
			}
			producer_add(pt,tmp);
			--readyNum;
			++flag;
		}
	}
	close(sockfd);
	exit(0);
}

thread_printf

#include <pool.h>

void* thread_printf(void* arg)
{
	pthread_detach(pthread_self());
	ptr=(pool_t*)arg;
	struct sigaction act,oact;
	sigemptyset(&act.sa_mask);
	act.sa_handler=&sig_usr;
	act.sa_flags=0;
	sigaction(SIGUSR1,&act,&oact);
	sigprocmask(SIG_SETMASK,&act.sa_mask,NULL);
	while(ptr->thread_shutdown)
	{
		sleep(1);
	}
	pthread_exit(NULL);
}

thread_destroy

#include <pool.h>

void thread_destroy(void* arg)
{
	pool_t* pt=(pool_t*)arg;
	pthread_cond_destroy(&pt->notEmpty);
	pthread_cond_destroy(&pt->notFull);
	pthread_mutex_destroy(&lock);

	free(pt->queue);
	free(pt->ctids);
	free(pt);
}

sig_usr

#include <pool.h>

void sig_usr(int n)
{
	printf("alive %d , busy %d , idel %d , cur %d , a/m %.2f%% , b/a %.2f%%\n",ptr->thread_alive,ptr->thread_busy,ptr->thread_alive-ptr->thread_busy,ptr->cur,(double)ptr->thread_alive/ptr->thread_max*100,(double)ptr->thread_busy/ptr->thread_alive*100);
}

main

#include <pool.h>

int main(void)
{
	sigset_t set,oset;
	sigemptyset(&set);
	sigaddset(&set,SIGUSR1);
	sigprocmask(SIG_SETMASK,&set,&oset);
	int sockfd=net_init(NULL,8080);
	pool_t* pt;
	epoll_init(sockfd,100000);
	pt=pool_init(100,10,1000);
	epoll_listen(sockfd,pt);
	if(!pt->thread_shutdown)
	{
		thread_destroy((void*)pt);
	}
	return 0;
}

client.c

#include<sock.h>

#define server_ip "192.168.206.150"
#define server_port 8080

int main()
{
    struct sockaddr_in addr;
    bzero(&addr,sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_port=htons(server_port);
    addr.sin_addr.s_addr=inet_addr(server_ip);
    // 创建套接字
    int sock=SOCKET(AF_INET,SOCK_STREAM,0);
    // 连接服务器
    int err=CONNECT(sock,(struct sockaddr*)&addr,sizeof(addr));
    if(err==-1)
    {
        // 若连接失败,关闭套接字并退出程序
        close(sock);
        exit(0);
    }
    char buf[1500];
    // 清空缓冲区
    bzero(buf,1500);
    // 接收服务器的首次响应
    RECV(sock,buf,sizeof(buf),0);
    printf("%s\n",buf);

    while(1)
    {
        // 清空缓冲区
        bzero(buf,sizeof(buf));
        if(fgets(buf,sizeof(buf),stdin)==NULL)
            // 若读取输入失败,退出循环
            break;
        // 发送请求到服务器
        SEND(sock,buf,strlen(buf),0);
        // 清空缓冲区
        bzero(buf,sizeof(buf));
        // 接收服务器响应
        RECV(sock,buf,sizeof(buf),0);
        printf("%s\n",buf);
    }
    // 关闭套接字
    close(sock);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值