简 易 版 线 程 池 模 型 学 习


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;
}

简 易 版 线 程 池 模 型 学 习相关推荐

  1. 简 易 版 的 进 程 池 模 型 学 习

    简 易  版 的 进 程 池 模  型 学 习 1.进程池流程 父进程流程 第一步: make_child 初始化子进程 循环创建子进程,并初始化父进程的子进程管理结构体数组 child, 通过 so ...

  2. Java高并发系列5-线程池

    Java高并发系列5-线程池 接上一篇Java并发系列4-并发容器我们继续 在编程中经常会使用线程来异步处理任务,但是每个线程的创建和销毁都需要一定的开销.如果每次执行一个任务都需要开个新线程去执行, ...

  3. 一期每日一GO群分享-flag、viper、协程池、异常处理

    1.11 flag库 今天介绍一个库flag,命令行程序常用,用来接受参数的. var (intflag intboolflag boolstringflag string )func init() ...

  4. 《HBase企业应用开发实战》—— 第3章 数 据 模 型

    本节书摘来自华章出版社<HBase企业应用开发实战>一 书中的第3章,第3.1节,作者:马延辉 孟鑫 李立松 ,更多章节内容可以访问云栖社区"华章计算机"公众号查看. ...

  5. 易传媒CTO程华奕:搭建私有DMP 你必须知道的几件事

    ZDNet至顶网软件频道消息:程华奕先生自2007年起加盟易传媒,担任首席技术官.他是易传媒创始团队的一员.在此之前,程华奕先生曾在eBay和PayPal担任首席工程师,并曾在美国多家科技公司任职,有 ...

  6. mysql 线程池源码模块_易语言Mysql线程池2.0模块源码

    易语言Mysql线程池2.0模块源码 易语言Mysql线程池2.0模块源码 系统结构:GetThis,初始化,关闭类线程,线程_测试,其他_附加文本,连接池初始化,取mysql句柄,释放mysql句柄 ...

  7. Golang的协程池设计

    转载地址:https://studygolang.com/articles/15477 使用Go语言实现并发的协程调度池阉割版,本文主要介绍协程池的基本设计思路,目的为深入浅出快速了解协程池工作原理, ...

  8. 白话 Golang 协程池

    文章目录 1.何为并发 2.并发的好处 3.Go 如何并发 4.G-P-M 调度模型 5.Go 程的代价 6.协程池的作用 7.简易协程池的设计&实现 8.开源协程池的使用 9.小结 参考文献 ...

  9. 深入浅出 Golang 协程池设计

    使用Go语言实现并发的协程调度池阉割版,本文主要介绍协程池的基本设计思路,目的为深入浅出快速了解协程池工作原理,与真实的企业协程池还有很大差距,本文仅供学习参考. 一.何为并发,Go又是如何实现并发? ...

最新文章

  1. NeurIPS 2021六篇杰出论文公布,谷歌工程师11年前论文获时间检验奖
  2. matlab 求解黄金分割率
  3. tp5循环查询语句_如何用Excel快速生成SQL语句,用过的人都说好
  4. python之4个小作业
  5. 《程序员》2月精彩内容:互联网应用架构面面观
  6. java 动态生成getset_通过get、set方法,动态生成对象
  7. nodejs missing script: dev_nodejs深入学习系列之v8基础篇
  8. shapefile中环状多边形处理问题
  9. 【今日CV 视觉论文速览】29 Nov 2018
  10. 1.9 使用PuTTY远程连接Linux 1.10 使用xshell连接Linux 1.11 PuTTY密钥认证 1.12 xshell密钥认证...
  11. python中read函数解释_Python内置函数解释教程,readwill(非常详细的代码演示截图),详解,看,了,就,会,很...
  12. Keil下Debug随笔
  13. 谈谈培训机构的“骗局“给新人一些建议
  14. 计算机表格斜杠怎么打,【2人回答】Excel表格中如何输入斜杠?-3D溜溜网
  15. RobotFramework-关键字-Wait Until Keyword Succeeds
  16. 详解电源反接使用MOS管保护电路原理及其优势
  17. mysql 商品库存表设计_库存数据库表设计
  18. PMP分享|不在挣扎中蜕变,就在安逸中消亡
  19. android微信分享长图功能,安卓分享9宫格图片到微信
  20. 一元线性回归方程C语言实现

热门文章

  1. Gridiew——表的内容居中
  2. VB.NET Visual Basic
  3. 安卓手机关闭底部键盘灯的方法(htc G11亲测有效)
  4. 解决Gradle生成Eclipse支持后,发布到Tomcat丢失依赖jar包的问题
  5. 多态的概念,特点与使用
  6. 兴奋的.NET@linux-Develop
  7. 脚本的力量:MSDN中一段代码的IronPython与PowerShell实现
  8. 动态规划之背包问题(C语言)
  9. java异常代码分析
  10. gitlab-ee使用mysql_在 GitLab 我们是如何扩展数据库的