简 易 版 线 程 池 模 型 学 习
来源:互联网 发布:临海停水通知软件 编辑:程序博客网 时间:2024/05/28 15:31
简 易 版 线 程 池 模 型 学 习
1、简易版线程池流程
1.初始化线程池
1、初始化队列, 队列头, 队列尾初始化, 队列能力初始化( 队列长度),队列锁初始化线程池条件变量,给子线程赋入口函数,为线程池的子线程的线程 ID 申请空间,线程池是否启动标志初始化为 02.启动线程池循环启动子线程, 设置线程池启动标志设置为 13.主线程启动 listen, 接收客户端请求加锁, 然后将接收到的 rs_fd 放入到 que 队列中, 解锁, pthread_cond_signal 等待在对应条件上的子线程注意:在使用队列时,需要将相关函数封装到一个.c文件里面,为了以后 的代码重用。
2、部分数据结构
队列数据结构typedef struct tag_node{ int newfd; struct tag_node *pnext;}node_t,*pnode_t;typedef struct { pnode_t phead,ptail; //定义头尾指针 int capability; //可以承载最多业务的最大能力 int size; //当前队列中的任务业务数 pthread_mutex_t mutex; //定义队列锁}que_t,*pque_t;线程池数据结构及网络发送数据的数据结构--小火车模型typedef struct{ //所有的数据结构 que_t que; //队列 pthread_cond_t cond; //定义线程条件变量 pfunc downfile; //定义子线程入口地址函数 pthread_t *pth; //线程ID的数组名,即首地址 int pth_num; //创建的线程数 short startflag; //线程池启动标志}factory,*pfac;typedef struct{ int len; char buf[1000];}train,*ptrain;
3、需要完成的部分功能函数
队列的部分功能函数:void que_init(pque_t);void que_insert(pque_t ,pnode_t);void que_get(pque_t ,pnode_t *);线程功能函数的:void factory_init(pfac p,int pth_num,pfunc pth_handle);void factory_start(pfac p);void send_data(int);int send_n(int ,char *,int);
4、头文件
//head.h#ifndef __HEAD_H__#define __HEAD_H__#include<sys/stat.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <sys/select.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <netdb.h>#include <string.h>#include <sys/types.h>#include <unistd.h>#include <stdlib.h>#include <sys/epoll.h>#include<sys/wait.h>#include<pthread.h>#endif//work_que.h#ifndef __WORK_QUE_H__#define __WORK_QUE_H__#include"head.h"#define CAP 1000 typedef struct tag_node{ int newfd; struct tag_node *pnext;}node_t,*pnode_t;typedef struct { pnode_t phead,ptail; //定义头尾指针 int capability; //可以承载最多业务的最大能力 int size; //当前队列中的任务业务数 pthread_mutex_t mutex; //定义队列锁}que_t,*pque_t;void que_init(pque_t);void que_insert(pque_t ,pnode_t);void que_get(pque_t ,pnode_t *);#endif//factory.h#ifndef __FACTORY_H__#define __FACTORY_H__ #include"head.h"#include"work_que.h"typedef void *(*pfunc)(void *);#define FILENAME "file"typedef struct{ //所有的数据结构 que_t que; //队列 pthread_cond_t cond; //定义线程条件变量 pfunc downfile; //定义子线程入口地址函数 pthread_t *pth; //线程ID的数组名,即首地址 int pth_num; //创建的线程数 short startflag; //线程池启动标志}factory,*pfac;typedef struct{ int len; char buf[1000];}train,*ptrain;void factory_init(pfac p,int pth_num,pfunc pth_handle);void factory_start(pfac p);void send_data(int);int send_n(int ,char *,int);#endif
5、主函数代码
#include"factory.h"void *pth_handle(void *p){ pfac pf=(pfac)p; pque_t pq=&pf->que; pnode_t pcur; //要拿的节点,因为一会儿要free掉 while(1) { pthread_mutex_lock(&pq->mutex); //拿节点之前,加锁 //且首先判断队列为不为空 if(NULL==pq->phead) { //为空子线程就等待 pthread_cond_wait(&pf->cond,&pq->mutex); } //否则,先拿到节点,解锁后,进行服务,传文件 que_get(pq,&pcur); //拿节点 pthread_mutex_unlock(&pq->mutex); //解锁 send_data(pcur->newfd); //发送文件 free(pcur); //释放掉节点 }}int main(int argc,char **argv){ if(4!=argc) { printf("please input IP PORT PTHREAD_NUM\n"); return -1; } factory p; bzero(&p,sizeof(p)); int pth_num=atoi(argv[3]); factory_init(&p,pth_num,pth_handle); factory_start(&p); int sfd; sfd=socket(AF_INET,SOCK_STREAM,0); if(-1==sfd) { perror("socket"); return -1; } struct sockaddr_in ser; memset(&ser,0,sizeof(ser)); ser.sin_family=AF_INET; ser.sin_port=htons(atoi(argv[2])); //需要把它置为网络字节序 ser.sin_addr.s_addr=inet_addr(argv[1]); int ret; ret=bind(sfd,(struct sockaddr *)&ser,sizeof(ser)); if(-1==ret) { perror("bind"); return -1; } listen(sfd,pth_num); int newfd; pnode_t pnew; //拿节点 pque_t pq=&p.que; //为了后面的书写方便 //主线程接受请求,插入队列,子线程服务请求,拿走队列节点 while(1) { newfd=accept(sfd,NULL,NULL);//这里是第二个是客户端的信息 pnew=(pnode_t)calloc(1,sizeof(node_t)); //这是节点呀 pnew->newfd=newfd; //将连接的描述符给申请空间的新节点 pthread_mutex_lock(&pq->mutex); //插入节点前先加锁 que_insert(pq,pnew); //第二个参数已经是指针了 pthread_mutex_unlock(&pq->mutex); //插入后在解锁 //由于插入新节点后,就应该通知子线程有任务到达 pthread_cond_signal(&p.cond); //不要混淆呀 }}
6、队列部分函数实现work_que.c
#include"work_que.h"void que_init(pque_t que){ que->capability=CAP; pthread_mutex_init(&que->mutex,NULL);} void que_insert(pque_t pq,pnode_t pnew){ if(NULL==pq->ptail) //若队列为空 { pq->phead=pnew; pq->ptail=pnew; //头尾指针都指向pnew }else{ //否则,进行尾插法 pq->ptail->pnext=pnew; pq->ptail=pnew; } pq->size++; //操作完后,大小自动加一,表示有新请求} void que_get(pque_t pq,pnode_t *pcur) //拿是拿指向该节点的指针{ *pcur=pq->phead; //头删--即从头部取节点 pq->phead=pq->phead->pnext; //拿完之后需要在判断是否为空 if(NULL==pq->phead) { pq->ptail=NULL; //若为空将尾指针也置为NULL } pq->size--;}
7、线程池工厂功能函数
#include"factory.h"void factory_init(pfac p,int pth_num,pfunc pth_handle) //不要混淆呀{ que_init(&p->que); pthread_mutex_init(&p->que.mutex,NULL); pthread_cond_init(&p->cond,NULL); p->downfile=pth_handle; p->pth=(pthread_t *)calloc(pth_num,sizeof(pthread_t)); p->pth_num=pth_num; p->startflag=0;}void factory_start(pfac p){ int i; if(0==p->startflag) { for(i=0;i<p->pth_num;i++) { pthread_create(p->pth+i,NULL,p->downfile,p); } p->startflag=1; //将线程启动标志位置为1(即启动) }}
8、发送文件及循环发送功能函数
#include"factory.h"void send_data(int newfd){ train t; memset(&t,0,sizeof(t)); strcpy(t.buf,FILENAME); t.len=strlen(FILENAME); printf("the strcpy t.buf is %s, len =%d\n",t.buf,t.len); //先发文件名 int ret; ret=send_n(newfd,(char *)&t,t.len+4); if(ret==-1) { perror("send"); return; } int fd=open(FILENAME,O_RDONLY); if(-1==fd) { perror("open"); return; } struct stat filestat; fstat(fd,&filestat); t.len=sizeof(long); memcpy(t.buf,&filestat.st_size,sizeof(filestat.st_size)); send_n(newfd,(char*)&t,4+t.len); while(memset(t.buf,0,sizeof(t.buf)),(t.len=read(fd,t.buf,sizeof(t.buf)))>0) { send_n(newfd,(char *)&t,t.len+4); } t.len=0; send_n(newfd,(char *)&t,4+t.len); close(newfd); close(fd);}#include"factory.h"int send_n(int sfd,char *p,int len){ int total=0,ret; while(total<len) { ret=send(sfd,p+total,len-total,0);//取出每一次发送了多少个 total=total+ret; } return 0;}int recv_n(int sfd,char *p,int len ){ int total=0,ret; while(total<len) { ret=recv(sfd,p+total,len-total,0); total=total+ret; } return 0;}
9、客户端程序
#include<time.h>#include <sys/stat.h>#include<errno.h>#include <fcntl.h>#include <signal.h>#include <sys/select.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <netdb.h>#include <string.h>#include <sys/types.h>#include <unistd.h>#include <stdlib.h>#include <sys/epoll.h>#include<sys/wait.h>typedef struct{ pid_t pid; int tfds; short busy;}child,*pchild;void send_fd(int fdw,int fd);void recv_fd(int fdr,int* fd);void make_child(pchild p,int len);void child_handle(int fdr);int recv_n(int,char *,int);
#include"func.h"int send_n(int sfd,char *p,int len){ int total=0,ret; while(total<len) { ret=send(sfd,p+total,len-total,0);//取出每一次发送了多少个 total=total+ret; } return 0;}int recv_n(int sfd,char *p,int len ){ int total=0,ret; while(total<len) { ret=recv(sfd,p+total,len-total,0); total=total+ret; } return 0;}
10、客户端主程序
#include"func.h"int main(int argc,char **argv){ if(3!=argc) { printf("error argcs!\n"); return -1; } int sfd; sfd=socket(AF_INET,SOCK_STREAM,0); if(-1==sfd) { perror("socket"); return -1; } struct sockaddr_in ser; memset(&ser,0,sizeof(ser)); int ret,ret1; ser.sin_family=AF_INET; ser.sin_port=htons(atoi(argv[2])); ser.sin_addr.s_addr=inet_addr(argv[1]); ret=connect(sfd,(struct sockaddr*)&ser,sizeof(ser)); int len; char buf[1000]={0}; recv_n(sfd,(char *)&len,sizeof(len)); //先接受文件名 recv_n(sfd,buf,len); int fd=open(buf,O_WRONLY|O_CREAT,0666); if(-1==fd) { perror("open"); return -1; } recv_n(sfd,(char *)&len,sizeof(len)); //在发送文件大小 long file_len; recv_n(sfd,(char*)&file_len,len); long l=0; time_t now,check; time(&now); check=now; while(1) { recv_n(sfd,(char *)&len,sizeof(len)); if(len>0) { l=l+len; memset(buf,0,sizeof(buf)); recv_n(sfd,buf,len);//接受完后就要写到袭击者边新建的文件里 write(fd,buf,len);//接受多少就写多少 time(&now); if(now>check+1) { printf("Now Data is %5.2f%s\r",100*(double)l/file_len,"%"); fflush(stdout); check=now; } }else{ printf("Down load successful!\n"); break; } } close(fd); close(sfd); return 0;}
阅读全文
0 1
- 简 易 版 线 程 池 模 型 学 习
- 简 易 版 的 进 程 池 模 型 学 习
- 学与习
- 学 习 总 结
- 学《易》札记
- 简学Oracle
- 简学javaScript技术
- 简学jQuery技术
- 学
- 学
- 学!!
- 学
- 学
- 学
- 黑马程序员:JavaSE的 课 程 学 习
- 简学数据库设计总结
- 读jedis学对象池
- 少林武学英文版
- PoEdu_python_Lesson005_回顾以及作业讲解
- spring RestTemplate用法详解
- cvCreateFileCapture读取AVI格式视频返回NULL
- 单片机小知识总结
- jenkins,maven--安装配置
- 简 易 版 线 程 池 模 型 学 习
- 解决AndroidStudio导入项目在 Building gradle project info 一直卡住
- <a> 标签下的下划线
- 通过maven生成自定义的jar包
- Android uiautomatorviewer出现Unable to connect to adb. Check if adb is installed correctly解决办法
- Android Studio Live Templates使用详解,提高敲代码的速度
- stm32 pwm的原理及主要参数的意义
- 正则表达式的用法
- Git使用教程