雙向鏈表實現線程池 用於TCP併發連接

簡述:自我感覺對C指針瞭解的還是比較透徹,能夠運用自如,一方面練習一下多線程編程,另一方面練習一下數據結構鏈表。

但是完成的過程中,各種問題還是撲面而來,共花了2個小時完成了此線程池來實現TCP併發連接,創建固定數目的線程

時間倉促,可能有某些指針未釋放,或者還沒完善的地方,希望能共同討論。

雙向鏈表提高掃描速度,信號等待用while保護,防止驚羣,在任務提取和加入過程動態維護鏈表,防止鏈表過長和冗餘。

創建線程,初始化屬性爲DETEACH,避免人爲對子線程的回收。



#include "unp.h"
#include <assert.h>
typedef struct demytask {							/*任務*/
	//void 				*(*func)(void *arg);			/*套接字處理函數指針*/
	void					*data;						/*連接套接字*/
	struct demytask		*next;						/*後向索引*/
	struct demytask		*prev;						/*後向索引*/
}task;
typedef struct pool {
	pthread_mutex_t 	mutex;				/*鎖和條件*/
	pthread_cond_t	cond;
	int				nthreads;			/*線程池中線程數*/
	int				totaltasks;			/*線程池中總的任務數*/
	int				runtasks;			/*正在服務的任務數*/
	int				shut;				/*線程池關閉狀態*/
	int				waittasks;			/*等待空閒線程的任務數*/
	task				*head;				/*任務頭指針*/
	task				*tail;				/*任務尾指針*/
	/*pthread_t	*threads*/				/*線程ID數組,暫無用*/
}thread_pool;

thread_pool	*pool;						/*線程池指針*/

void *thread_func(void *arg);			/*線程函數*/
void inital_thread_poll(int num);		/*線程池初始化*/
void insert_task_2_poll(/*void *(*func)(void *),*/ void *data);/*增加任務*/
void del_task_2_poll();				/*刪除任務*/
void serve_machine(int connfd) ;		/*爲客戶端服務函數*/
void clear_pool(int	signo) ;			/*線程池資源釋放*/


	
int inital_thread_poll(int num) {
    pthread_attr_t      attr;
    pthread_t       pid;
    int                 i, err;
    pool = (thread_pool *)malloc(sizeof(thread_pool));  /*在堆上分配*/
    if(pool == NULL) {
    #ifdef PRT
        PST("Malloc error");
    #endif
        return -1;
    }
    assert(pool != NULL);
    pthread_mutex_init( &(pool->mutex), NULL);      /*鎖*/
    pthread_cond_init( &(pool->cond), NULL);        /*條件*/
    pool->nthreads = num;           
    pool->totaltasks = pool->runtasks = 0;      /*當前總接受的任務數和運行任務數*/
    pool->shut = 0;                                                     /*關閉標誌*/
    pool->head = pool->tail = NULL;
    pool->head = pool->tail = malloc(sizeof(task));     /*初始化頭尾指針*/          
    pthread_attr_init( &attr);                      /*屬性*/
    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED);
    for( i =0; i < num; i++) {
        if((err = pthread_create( &pid, &attr, thread_func, NULL)) != 0) {  /*創建線程*/
            return err;
        }
    }
    pthread_attr_destroy( &attr);
    return 0;
}
/*
*給線程池中加入任務
*/
void insert_task_2_poll(/*void *(*func)(void *),*/ void *data) { /*添加任務*/
    task *mytask;
    mytask = (task *)malloc(sizeof(task));          /*在堆上分配*/
    if(mytask == NULL) {
    #ifdef PRT
        PST("Malloc task error");
    #endif 
        return;
    }
/*  mytask->func = func;*/
    mytask->data = data;
    pthread_mutex_lock(&(pool->mutex));
    pool->tail->next = mytask;
    mytask->prev = pool->tail;
    pool->tail = mytask;
    pool->tail->next = NULL;
    pool->totaltasks ++;                        /*任務數加1*/
    pool->waittasks ++;                     /*等待處理的任務數加1*/
#ifdef PRT
        printf("Add a task ,the total tasks is %d, waittask is %d\n",pool->totaltasks,pool->waittasks);
#endif
    pthread_cond_signal(&(pool->cond));/*喚醒等待任務的線程*/
    pthread_mutex_unlock(&(pool->mutex));
    return;
}
/*
*刪除線程池中尾任務
*/
void del_task_2_poll() {                /*刪除任務*/
/*  pthread_mutex_lock(&(pool->mutex));*/
    free(pool->tail->data);
    pool->tail->data = NULL;
    pool->tail = pool->tail->prev;
    free(pool->tail->next);
    pool->tail->next = NULL;
    pool->totaltasks --;
#ifdef PRT
        printf("Delete a task ,the total tasks is %d, waittask is %d\n",pool->totaltasks,pool->waittasks);
#endif
/*  pthread_mutex_lock(&(pool->mutex));*/
}
/*
*線程函數
*/
void *thread_func(void *arg) {              /*等待任務,無則阻塞*/
    /*void  *(*functemp)(void *);*/
    int     connfd;
    for( ; ;) {
        pthread_mutex_lock(&(pool->mutex));
        while(pool->waittasks == 0) 
            pthread_cond_wait(&(pool->cond), &(pool->mutex));
    /*  functemp = pool->tail->func;*/
        connfd = *((int *)(pool->tail->data));
        pool->runtasks ++;                  /*處理過的任務數*/
        pool->waittasks --;                 /*等待處理的任務數*/
        del_task_2_poll();                      /*釋放這個任務*/
        pthread_mutex_unlock(&(pool->mutex));   /*解鎖,使其他線程可以等待其他任務*/
        serve_machine(&connfd);             /*任務開始執行*/
    }
}
/*
*釋放線程池資源
*/
void clear_pool(int signo) {                /*清除線程池*/
    task    *temp;
#ifdef PRT
    printf("\n服務器正在關閉...\n");
#endif
    pthread_mutex_lock(&(pool->mutex));
    temp = pool->head->next;
    for(; temp != NULL; temp = pool->head->next) {
        free(pool->head->data);
        pool->head->data = NULL;
        if(pool->head->prev != NULL){
            free(pool->head->prev);
            pool->head->prev = NULL;
        }
        free(pool->head);
        pool->head = NULL;
        pool->head = temp;
    }
    /*free(temp);*/
    pthread_mutex_unlock(&(pool->mutex));
    pthread_mutex_destroy(&(pool->mutex));
    pthread_cond_destroy(&(pool->cond));
    free(pool);
    pool = NULL;
    exit(0);
}




int main(int argc, char **argv)
{
	int					listenfd, *connfd, num;
	socklen_t				clilen;
	struct sockaddr_in		cliaddr, servaddr;
	const int 				on = 1;
	if( argc != 2)
		err_quit("argc");
	listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	num = atoi(argv[1]);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family      = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port        = htons(SERV_PORT);
	setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &on,	sizeof(int));
	Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
	inital_thread_poll(num);						/*初始化線程池*/
	signal(SIGINT,clear_pool);						/*中斷時,釋放資源*/
	Listen(listenfd, LISTENQ);
	for ( ; ; ) {
		clilen = sizeof(struct sockaddr);
		connfd = (int * )malloc(sizeof(int));				/*每個連接一個*/
		*connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
		 insert_task_2_poll(connfd);				/*增加任務,投入到線程池*/
	}
	clear_pool(SIGINT);
	exit(0);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章