簡述:自我感覺對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);
}