UNIX网络编程卷1 server程序设计范式8 预先创建线程,由主线程调用accept
2017-07-24 13:19
309 查看
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie
1.程序启动阶段创建一个线程池之后仅仅让主线程调用 accept 并把客户连接传递给池中某个可用线程。
1.程序启动阶段创建一个线程池之后仅仅让主线程调用 accept 并把客户连接传递给池中某个可用线程。
//用于维护关于每一个线程基于信息的 Thread 结构 typedef struct { pthread_t thread_tid; /* 线程 ID */ long thread_count; /* 处理的连接数 */ } Thread; Thread *tptr; /* Thread 结构指针,指向一个用 calloc 产生的 Thread结构数组 */ //定义存放已连接套接字描写叙述符的共享数组 #define MAXNCLI 32 int clifd[MAXNCLI], iget, iput; pthread_mutex_t clifd_mutex; pthread_cond_t clifd_cond; /* include serv08 */ #include "unpthread.h" #include "pthread08.h" static int nthreads; pthread_mutex_t clifd_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t clifd_cond = PTHREAD_COND_INITIALIZER; int main(int argc, char **argv) { int i, listenfd, connfd; void sig_int(int), thread_make(int); socklen_t addrlen, 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); else err_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 处理函数 void sig_int(int signo) { int i; void pr_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); } void thread_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) { int connfd; void web_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); } }
相关文章推荐
- UNIX网络编程卷1 服务器程序设计范式8 预先创建线程,由主线程调用accept
- UNIX网络编程卷1 server程序设计范式7 预先创建线程,以相互排斥锁上锁方式保护accept
- UNIX网络编程卷1 服务器程序设计范式7 预先创建线程,以互斥锁上锁方式保护accept
- UNIX网络编程卷1 服务器程序设计范式3 预先派生子进程,以文件上锁方式保护accept
- C#中创建线程的方式,以及主线程和子线程之间的资源调用
- UNIX网络编程卷1 服务器程序设计范式2 预先派生子进程,每个子进程调用accept
- 多进程并发编程----基于高级的预先创建进程池(accept使用线程上锁)的模型
- Java线程的传说(3)——如何关闭一个正在accept的ServerSocket?
- 创建2个线程及一个主线程
- 多线程,成员函数内创建线程,线程函数调用类内的其他成员函数
- 不要在dll及ocx的CXXXApp::InitInstance中调用创建线程及关闭线程的操作
- 创建线程后为什么马上调用CloseHandle()来关闭句柄
- Qt多线程之一:子线程中创建的对象不应再其他线程中被调用,包括使用槽函数的形式
- 3、prefork or pre threaded 预先创建进程和线程
- 创建线程后为什么马上调用CloseHandle()来关闭句柄
- 创建线程 windows程序设计 王艳平版
- 【Linux学习】pthread_create主线程与创建的新线程之间退出关系
- Control Invoke详解(从不是创建控件的线程调用)
- 调用不是本线程创建的windows控件会报错
- QT中线程调用GUI主线程控件的问题