预分配线程(prethreading)

相关网络编程函数:http://blog.csdn.net/somehow1002/article/details/72648743

预分配线程(prethreading)是让服务器在启动阶段创建一个线程池,每个客户请求由当前可用线程池中的某个闲置线程处理


1.初始版本:每个客户一个线程

int main(int argc,char **argv){
    int listenfd,connfd;
    void sig_int(int);
    void *doit(void *);
    pthread_t tid;
    socklen_t clilen,addrlen;
    struct sockaddr *cliaddr;
    
    if(argc==2)
        listenfd=Tcp_listen(NULL,argv[1],&addrlen);
    else if(argc==3)
        listenfd=Tcp_listen(argv[1],argv[2],&addrlen);
    else
        err_quit("usage:server [<host>] <port#>");
    cliaddr=malloc(addrlen);
    
    signal(SIGNINT,sig_int);
    
    for(;;){
        chilen=addrlen;
        connfd=accept(listenfd,cliaddr,&clilen);
        pthread_create(&tid,NULL,&doit,(void *)connfd);
    }
}
void *doit(void *arg){
    void str_echo(int);
    
    pthread_detach(pthread_self());
    str_echo((int)arg);
    close((int)arg);
    return NULL;
}


2.每个线程各自accept
上一个版本是来一个客户创建一个线程,但是很明显,预先派生一个子线程池比现场创建线程性能更加高效。
预先创建线程池程序

typedef struct{
    pthread_t thread_tid;
    long thread_count;
}Thread;
Thread *tptr;

int listenfd,nthreads;
socklen_t addrlen;
pthread_mutex_t mlock=PTHREAD_MUTEX_INITALIZER;

int main(int argc,char **argv){
    int i;
    void sig_int(int),thread_make(int);
    
    if(argc==3)
        listenfd=Tcp_listen(NULL,argv[1],&addrlen);
    else if(argc==4)
        listenfd=Tcp_listen(argv[1],argv[2],&addrlen);
    else
        err_quit("usage:server [<host>] <port#> <#threads>");
    nthreads=atoi(argv[argc-1]);
    tptr=calloc(nthreads,sizeof(Thread));
    
    for(i=0;i<nthreads;i++)
        thread_make(i);
    
    signal(SIGINT,sig_int);
    
    for(;;)
        pause();
}

void thread_make(int i){
    void *thread_main(void *);
    
    pthread_create(&tptr[i].thread_tid,NULL,&thread_main,(void *)i);
    return;
}

void * thread_main(void *arg){
    int connfd;
    void str_echo(int);
    socklen_t clilen;
    struct sockaddr *cliaddr;
    
    cliaddr=malloc(addrlen);
    
    printf("thread %d starting\n",(int)arg);
    for(;;){
        clilen=addrlen;
        //accept进行了加锁保护
        pthread_mutex_lock(&mlock);
        connfd=accept(listenfd,cliaddr,&clilen);
        pthread_mutex_unlock(&mlock);
        tptr[(int)arg].thread_count++;
        
        str_echo(connfd);
        close(connfd);
    }
}

3.主线程统一accept
类似于进程的描述符传递版本,这一个版本的程序让主线程调用accept并吧每个客户端连接传递给线程池中某个可用线程。
不同于进程版本的是,描述符的传递并不需要使用unix域协议。既然所有线程和套接字都在同一个进程内,那么我们就没有必要把一个描述符从一个线程传递到另一个线程。这个版本的实现是通过一个全局数组clifd。主线程将描述符存入,然后线程池中某个线程取出描述符。clifd数组的维护是通过互斥锁和条件变量实现的。

#define MAXNCLI 32
int clifd[MAXNCLI],iget,iput;
pthread_mutex_t clifd_mutex=PTHREAD_MUTEX_INITALIZER;
pthread_cond_t clifd_cond=PTHREAD_MUTEX_INITALIZER;

static int nthreads;
int main(int argc,char **argv){
    int i,listenfd,connfd;
    void sig_int(int),thread_make(int);
    socklen_t addrlen,clilen;
    struct sockaddr *cliaddr;
    
    if(argc==3)
        listenfd=Tcp_listen(NULL,argv[1],&addrlen);
    else if(argc==4)
        listenfd=Tcp_listen(argv[1],argv[2],&addrlen);
    else
        err_quit("usage:server [<host>] <port#> <#threads>");
    cliaddr=malloc(addrlen);
    
    nthreads=atoi(argv[argc-1]);
    tptr=calloc(nthreads,sizeof(Thread));
    iget=iput=0;
    
    for(i=0;i<nthreads;i++)
        thread_make(i);
    
    signal(SIGINT,sig_int);
    
    for(;;){
        clilen=addrlen;
        connfd=accept(listenfd,cliaddr,&clilen);
        
        pthread_mutex_lock(&clifd_mutex);
        clifd[iput]=connfd;
        if(++iput==MAXNCLI)
            iput=0;
        if(iput==iget)
            err_quit("iput=iget=%d",iput);
        pthread_cond_signal(&clifd_cond);
        pthread_mutex_unlock(&clifd_mutex);
    }
}
void thread_make(int i){
    void *thread_main(void *);
    pthread_create(&tptr[i].thread_tid,NULL,&thread_main,(void *)i);
    return ;
}
void *thread_main(void *arg){
    int connfd;
    void str_ehco(int);
    
    printf("thread %d starting\n",(int)arg);
    for(;;){
        pthread_mutex_lock(&clifd_mutex);
        while(iget==iput)
            pthread_cond_wait(&clifd_cond,&clifd_mutex);
        connfd=clifd[iget];
        if(++iget==MAXNCLI)
            iget=0;
        pthread_mutex_unlock(&clifd_mutex);
        tptr[(int)arg].thread_count++;
        
        str_echo(connfd);
        close(connfd);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hober.z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值