双向链表实现线程池 用于TCP并发连接

原创 2012年03月28日 19:16:44

简述:自我感觉对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);
}


MarioTCP:一个可单机支持千万并发连接的TCP服务器

请注意:过去几年有不少朋友加我,心想对不住大家了,建个群聚聚大家伙,请大家群里畅所欲言…请加QQ群:564994650, 里面有不少linux c的研发同学:)MrioTCP,超级马里奥,顾名思义,他...
  • everlastinging
  • everlastinging
  • 2013-09-02 08:58:39
  • 20906

【网络编程】MarioTCP

0、参考博客 《MarioTCP_一个可单机支持千万并发连接的TCP服务器 - JohanFong - CSDN博客》 http://blog.csdn.net/everlastinging/a...
  • u010168781
  • u010168781
  • 2017-08-23 19:56:12
  • 273

用MarioTCP库实现一个单机10亿级的百万并发长连接

注:如果用此服务器做变长data的传输,请在业务处理函数中为input buffer增加清空功能(一行memset搞定;也可以在mariotcp核心代码mario_network.c的read功能中增...
  • shuyun123456789
  • shuyun123456789
  • 2017-03-28 09:23:57
  • 1116

MarioTCP:一个单机可日30亿的百万并发长连接服务器

  • 2014年11月18日 23:52
  • 12KB
  • 下载

单机25万tcp长连接后,gc cpu前后比对图

这里不变内存占用量大。因为这是25万长连接保持后的内存占用情况。 【图一】中红圈处,gc acctivity 即gc活动占用的cpu很低。【图二】cpu gc活动占用的cpu很高。对应下午4.46分...
  • wh0426
  • wh0426
  • 2016-03-30 17:20:33
  • 210

高性能、高并发TCP服务器(多线程调用libevent)

本文讲述的TCP服务器是模仿memcache中的TCP网络处理框架,其中是基于libevent网络库的。 主线程只处理监听客户端的连接请求,并将请求平均分配给子线程。 子线程处理与客户端的连接以及...
  • I_am_JoJo
  • I_am_JoJo
  • 2012-05-22 09:58:14
  • 30178

如何从一台客户机向服务机发起40亿TCP长连接?

这绝不是标题党!其实这是一篇“科普”文章,讲述了关于“socket=((client_ip:client_port)-(server_ip:server_port),pocotol)”的一个普遍的误解...
  • lostaway
  • lostaway
  • 2014-09-21 14:40:39
  • 4702

libevent+protobuf轻松搭建tcpserver

0. 基础代码       // 设置某fd为O_NONBLOCK模式       int set_non_block(int fd);       // server端socket流程...
  • educast
  • educast
  • 2014-06-27 10:18:03
  • 6138

Mario tcp

转自:http://www.cnblogs.com/felixjia/p/3722245.html MarioTCP, take it.. MrioTCP,超级马里奥,顾名思义,他...
  • dd809477679
  • dd809477679
  • 2015-06-09 21:27:24
  • 303

使用起来超级简单的一个<em>TCP</em>通信库

使用起来超级简单的一个TCP通信库 立即下载 上传者: fo1_sky 时间: 2009-12-07 综合评分: 0 积分/C币:3 【网络编程】<em>MarioTCP</em> modbus TCP 通讯类库和...
  • 2018年04月16日 00:00
收藏助手
不良信息举报
您举报文章:双向链表实现线程池 用于TCP并发连接
举报原因:
原因补充:

(最多只允许输入30个字)