zoukankan      html  css  js  c++  java
  • UNIX网络编程卷1 server程序设计范式8 预先创建线程,由主线程调用accept

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


    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 ", 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 ", (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); } }


  • 相关阅读:
    后台获取不规则排列RadioButton组的值
    通过使用ScriptManager.RegisterStartupScript,呈现后台多次使用alert方法
    通过获取DNS解析的未转义主机名,区分测试环境和正式环境代码
    Autolayout自动布局
    JSON和XML
    物理引擎UIDynamic
    呈现样式UIModalPresentation
    多线程 GCD
    FMDB数据库框架
    SQLite编码
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/7228437.html
Copyright © 2011-2022 走看看