简 易 版 线 程 池 模 型 学 习

来源:互联网 发布:临海停水通知软件 编辑:程序博客网 时间: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;}