UNIX网络编程卷1 服务器程序设计范式8 预先创建线程,由主线程调用accept

来源:互联网 发布:上海大学云计算平台 编辑:程序博客网 时间:2024/04/30 03:21

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie


1.程序启动阶段创建一个线程池之后只让主线程调用 accept 并把客户连接传递给池中某个可用线程。

//用于维护关于每个线程基于信息的 Thread 结构typedef struct {  pthread_tthread_tid;/* 线程 ID */  longthread_count;/* 处理的连接数 */} Thread;Thread*tptr;/* Thread 结构指针,指向一个用 calloc 产生的 Thread结构数组 *///定义存放已连接套接字描述符的共享数组#defineMAXNCLI32intclifd[MAXNCLI], iget, iput;pthread_mutex_tclifd_mutex;pthread_cond_tclifd_cond;/* include serv08 */#include"unpthread.h"#include"pthread08.h"static intnthreads;pthread_mutex_tclifd_mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_tclifd_cond = PTHREAD_COND_INITIALIZER;intmain(int argc, char **argv){inti, listenfd, connfd;voidsig_int(int), thread_make(int);socklen_taddrlen, clilen;struct sockaddr*cliaddr;//1.创建监听套接字if (argc == 3)listenfd = Tcp_listen(NULL, argv[1], &addrlen);else if (argc == 4)listenfd = Tcp_listen(argv[1], argv[2], &addrlen);elseerr_quit("usage: serv08 [ <host> ] <port#> <#threads>");cliaddr = Malloc(addrlen);//2.增设一个命令行参数供用户指定预先派生的线程数nthreads = atoi(argv[argc-1]);tptr = Calloc(nthreads, sizeof(Thread));//iput 是主线程将往 clifd 数组中存放的下一个元素的下标//iget 是线程池中某个线程将从该数组中取出的下一个元素的下标iget = iput = 0;/* 4create all the threads *///3.调用 thread_make 创建各个线程for (i = 0; i < nthreads; i++)thread_make(i);/* only main thread returns *///4.设置中断信号 SIGINT 的处理函数Signal(SIGINT, sig_int);for ( ; ; ) {clilen = addrlen;//5.阻塞于 accept 等待用户连接connfd = Accept(listenfd, cliaddr, &clilen);//因为clifd 数组是所有线程共享的,所以要调用 pthread_mutex_lock 和 pthread_mutex_unlock 加以保护Pthread_mutex_lock(&clifd_mutex);clifd[iput] = connfd; //把已连接套接字存入 clifd 数组的下一个元素if (++iput == MAXNCLI) iput = 0;if (iput == iget) err_quit("iput = iget = %d", iput);//发送信号到条件变量信号Pthread_cond_signal(&clifd_cond);Pthread_mutex_unlock(&clifd_mutex);}}/* end serv08 *///中断信号 SIGINT 处理函数voidsig_int(int signo){inti;voidpr_cpu_time(void);//调用 pr_cpu_time 统计资源利用统计//在预先派生子进程的代码中还要先给每个子进程发送 SIGTERM 信号终止它们再统计。//这里由于是线程,而子线程与主线程是在同一个地址空间的,当主线程终止时,子线程也会终止。pr_cpu_time();for (i = 0; i < nthreads; i++)printf("thread %d, %ld connections\n", i, tptr[i].thread_count);exit(0);}voidthread_make(int i){void*thread_main(void *);//创建线程并使之执行 thread_main 函数,该函数的唯一参数是本线程在 Thread 结构数组中的下标Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *) i);return;/* main thread returns */}void *thread_main(void *arg){intconnfd;voidweb_child(int);printf("thread %d starting\n", (int) arg);for ( ; ; ) {//因为clifd 数组是所有线程共享的,所以要调用 pthread_mutex_lock 和 pthread_mutex_unlock 加以保护    Pthread_mutex_lock(&clifd_mutex);//若两者相等则无事可做,调用 pthread_cond_wait 在睡眠在条件变量上,等待主线程唤醒while (iget == iput)Pthread_cond_wait(&clifd_cond, &clifd_mutex);//得到要处理的套接字描述符connfd = clifd[iget];/* connected socket to service */if (++iget == MAXNCLI)iget = 0;Pthread_mutex_unlock(&clifd_mutex);tptr[(int) arg].thread_count++;//处理客户请求web_child(connfd);/* process request *///关闭已连接套接字Close(connfd);}}

1 0