UNIX網絡編程卷1 server程序設計範式8 預先建立線程,由主線程調用accept

本文爲senlie原創,轉載請保留此地址:http://blog.csdn.net/zhengsenlieweb


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); } } socket

相關文章
相關標籤/搜索