博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UNIX网络编程——客户/服务器程序设计示范(八)
阅读量:6886 次
发布时间:2019-06-27

本文共 3181 字,大约阅读时间需要 10 分钟。

    TCP预先创建线程服务器程序,主线程统一accept

 

            最后一个使用线程的服务器程序设计示范是在程序启动阶段创建一个线程池之后只让主线程调用accept并把每个客户连接传递给池中某个可用线程。

            本设计示范的问题在于主线程如何把一个已连接套接字传递给线程池中某个可用线程。这里有多个实现手段。我们原本可以如前使用描述符传递,不过既然所有线程和所有描述符都在同一个进程之内,我们没有必要把一个描述符从一个线程传递到另一个线程。接收线程只需知道这个已连接套接字描述符的值,而描述符传递实际传递的并非这个值,而是对这个套接字的一个引用,因而将返回一个不同于原值的描述符(该套接字的引用计数也被递增)。

typedef struct {  pthread_t		thread_tid;		/* thread ID */  long			thread_count;	/* # connections handled */} Thread;Thread	*tptr;		/* array of Thread structures; calloc'ed */#define	MAXNCLI	32int					clifd[MAXNCLI], iget, iput;pthread_mutex_t		clifd_mutex;pthread_cond_t		clifd_cond;
定义存放已连接套接字描述符的共享数组
07-10        我们还定义一个clifd数组,由主线程往中存入已接受的已连接套接字描述符,并由线程池中的可用线程从中取出一个以服务相应的客户。iput是主线程将往该数组中存入的下一个元素的下标,iget是线程池中某个线程将从该数组中取出的下一个元素的下标。这个有所有线程共享的数据结构自然必须得到保护,我们使用互斥锁和条件变量做到这一点。

#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;intmain(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: serv08 [ 
]
<#threads>"); cliaddr = Malloc(addrlen); nthreads = atoi(argv[argc-1]); tptr = Calloc(nthreads, sizeof(Thread)); iget = iput = 0; /* 4create all the threads */ for (i = 0; i < nthreads; i++) thread_make(i); /* only main thread returns */ 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); }}voidsig_int(int signo){ int i; void pr_cpu_time(void); pr_cpu_time(); for (i = 0; i < nthreads; i++) printf("thread %d, %ld connections\n", i, tptr[i].thread_count); exit(0);}

创建线程池

29-30    使用thread_make创建池中的每个线程。

等待客户连接

34-46    主线程大部分时间阻塞在accept调用中,等待各个客户连接的到达。一旦某个客户连接到达,主线程就把它的已连接套接字描述符存入clifd数组的下一个元素,不过需事先获取保护该数组的互斥锁。主线程还检查iput下标没有赶上iget下标(若赶上则说明该数组不够大),并发送信号到条件变量信号,然后释放互斥锁,以允许线程池中某个线程为这个客户服务。

#include	"unpthread.h"#include	"pthread08.h"voidthread_make(int i){	void	*thread_main(void *);	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 ( ; ; ) {    	Pthread_mutex_lock(&clifd_mutex);		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);	}}
等待未之服务的客户描述符
21-31      线程池中每个线程都试图获取保护clifd数组的互斥锁。获得之后就测试iput与iget,若两者相等则无事可做,于是通过调用pthread_cond_wait睡眠在条件变量上。主线程接受一个连接后将待用pthread_cond_signal向条件变量发送信号,以唤醒睡眠在其上的线程。若测得iput与iget不等则从clifd数组中取出下一个元素以获得一个连接,然后调用web_child。

转载于:https://www.cnblogs.com/hehehaha/p/6332537.html

你可能感兴趣的文章
【Spark 深入学习 07】RDD编程之旅基础篇03-键值对RDD
查看>>
汽车常识全面介绍 - 引擎概论
查看>>
教你如何拍好人像摄影
查看>>
python 闭包
查看>>
学习笔记-备份还原
查看>>
android WebView缩放时卡顿问题
查看>>
FastDFS搭建及java整合代码【转】
查看>>
nginx gzip压缩
查看>>
不要在该约炮的年纪谈佛系
查看>>
c++SDK c#调用_疑难杂症
查看>>
Git初始化项目 和 Gitignore
查看>>
CMakeList.txt设置OpenCv路径
查看>>
springboot mvc beetl模板 自定义错误的后缀问题
查看>>
ext常用属性
查看>>
PL/SQL连接64位Oracle配置方法
查看>>
socket解读,http和socket之长连接和短连接区别!
查看>>
洛谷——P1165 日志分析
查看>>
[GeekBand] C++ 基础知识之 The Big Three
查看>>
react Promise && Ref learning
查看>>
最长上升子序列(NlogN)总结
查看>>