C语言实现线程池
以前写过一篇关于如何使用多线程推升推送速度(http://www.cnblogs.com/bai-jimmy/p/5177433.html),能够到达5000qps,其实已经可以满足现在的业务,不过在看nginx的说明文档时,又提到nginx支持线程池来提升响应速度, 一直对如何实现线程池很感兴趣,利用周末的时间参考别人的代码,自己写了一个初级版,并且调通了,还没在实际开发中应用,不知道效果如何
代码如下:
pd_log.h
#ifndef __pd_log_
#define __pd_log_ #define LOG_DEBUG_PATH "debug.log"
#define LOG_ERROR_PATH "error.log" /**
* define log level
*/
enum log_level {
DEBUG = ,
ERROR =
}; #define error(...) \
logger(ERROR, __LINE__, __VA_ARGS__) #define debug(...) \
logger(DEBUG, __LINE__, __VA_ARGS__) #define assert(expr, rc) \
if(!(expr)){ \
error(#expr"is null or 0"); \
return rc; \
}
#endif
pd_log.c
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h> #include "pd_log.h" /**
* get now timestr
*/
static void get_time(char *time_str, size_t len) {
time_t tt;
struct tm local_time;
time(&tt);
localtime_r(&tt, &local_time);
strftime(time_str, len, "%m-%d %H:%M:%S", &local_time);
} /**
* log
*/
static void logger(int flag, int line, const char *fmt, ...) {
FILE *fp = NULL;
char time_str[ + ];
va_list args;
get_time(time_str, sizeof(time_str)); switch (flag) {
case DEBUG:
fp = fopen(LOG_DEBUG_PATH, "a");
if (!fp) {
return;
}
fprintf(fp, "%s DEBUG (%d:%d) ", time_str, getpid(), line);
break;
case ERROR:
fp = fopen(LOG_ERROR_PATH, "a");
if (!fp) {
return;
}
fprintf(fp, "%s ERROR (%d:%d) ", time_str, getpid(), line);
break;
default:
return;
} va_start(args, fmt);
vfprintf(fp, fmt, args);
va_end(args);
fprintf(fp, "\n"); fclose(fp);
return;
}
pd_pool.h
/**
* 线程池头文件
* @author jimmy
* @date 2016-5-14
*/
#ifndef __PD_POOL_
#define __PD_POOL_ /*任务链表*/
typedef struct task_s{
void (*routine)(void *);
void *argv;
struct task_s *next;
} pd_task_t; /*任务队列*/
typedef struct queue_s{
pd_task_t *head;
pd_task_t **tail;
size_t max_task_num;
size_t cur_task_num;
}pd_queue_t; /*线程池*/
typedef struct pool_s{
pthread_mutex_t mutex;
pthread_cond_t cond;
pd_queue_t queue;
size_t thread_num;
//size_t thread_stack_size;
}pd_pool_t; /*初始化线程池*/
//pd_pool_t *pd_pool_init(size_t thread_num, size_t thread_stack_size, size_t thread_max_num);
#endif
pd_poo.c
/**
* 线程池
* @author jimmy
* @date 2016-5-14
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h> #include <pthread.h> #include "pd_log.h"
#include "pd_log.c"
#include "pd_pool.h" /*tsd*/
pthread_key_t key; void *pd_worker_dispatch(void *argv){
ushort exit_flag = ;
pd_task_t *a_task;
pd_pool_t *a_pool = (pd_pool_t *)argv;
if(pthread_setspecific(key, (void *)&exit_flag) != ){
return NULL;
}
/*动态从任务列表中获取任务执行*/
while(!exit_flag){
pthread_mutex_lock(&a_pool->mutex);
/*如果此时任务链表为空,则需要等待条件变量为真*/
while(a_pool->queue.head == NULL){
pthread_cond_wait(&a_pool->cond, &a_pool->mutex);
}
/*从任务链表中任务开支执行*/
a_task = a_pool->queue.head;
a_pool->queue.head = a_task->next;
a_pool->queue.cur_task_num--;
if(a_pool->queue.head == NULL){
a_pool->queue.tail = &a_pool->queue.head;
}
/*解锁*/
pthread_mutex_unlock(&a_pool->mutex);
/*执行任务*/
a_task->routine(a_task->argv);
//core
free(a_task);
a_task = NULL;
}
pthread_exit();
} /**
* 根据线程数创建所有的线程
*/
static int pd_pool_create(pd_pool_t *a_pool){
int i;
pthread_t tid;
for(i = ; i < a_pool->thread_num; i++){
pthread_create(&tid, NULL, pd_worker_dispatch, a_pool);
}
return ;
} /**
* 线程退出函数
*/
void pd_pool_exit_cb(void *argv){
unsigned int *lock = argv;
ushort *exit_flag_ptr = pthread_getspecific(key);
*exit_flag_ptr = ;
pthread_setspecific(key, (void *)exit_flag_ptr);
*lock = ;
} /**
* 线程池初始化
*/
pd_pool_t *pd_pool_init(size_t thread_num, size_t thread_max_num){
pd_pool_t *a_pool = NULL;
a_pool = calloc(, sizeof(pd_pool_t));
if(!a_pool){
error("pool_init calloc fail: %s", strerror(errno));
return NULL;
}
a_pool->thread_num = thread_num;
//初始化队列参数
a_pool->queue.max_task_num = thread_max_num;
a_pool->queue.cur_task_num = ;
a_pool->queue.head = NULL;
a_pool->queue.tail = &a_pool->queue.head;
//初始化tsd
if(pthread_key_create(&key, NULL) != ){
error("pthread_key_create fail: %s", strerror(errno));
goto err;
}
//初始化互斥锁
if(pthread_mutex_init(&a_pool->mutex, NULL) != ){
error("pthread_mutex_init fail: %s", strerror(errno));
pthread_key_delete(key);
goto err;
}
//初始化条件变量
if(pthread_cond_init(&a_pool->cond, NULL) != ){
error("pthread_cond_init fail: %s", strerror(errno));
pthread_mutex_destroy(&a_pool->mutex);
goto err;
}
//创建线程池
if(pd_pool_create(a_pool) != ){
error("pd_pool_create fail: %s", strerror(errno));
pthread_mutex_unlock(&a_pool->mutex);
pthread_cond_destroy(&a_pool->cond);
goto err;
}
return a_pool;
err:
free(a_pool);
return NULL;
} /**
* 向线程池中添加任务..
*/
int pd_pool_add_task(pd_pool_t *a_pool, void (*routine)(void *), void *argv){
pd_task_t *a_task = NULL;
a_task = (pd_task_t *)calloc(, sizeof(pd_task_t));
if(!a_task){
error("add task calloc faile: %s", strerror(errno));
return -;
}
a_task->routine = routine;
a_task->argv = argv;
a_task->next = NULL;
/*加锁*/
pthread_mutex_lock(&a_pool->mutex);
if(a_pool->queue.cur_task_num >= a_pool->queue.max_task_num){
error("cur_task_num >= max_task_num");
goto err;
}
/*将任务放到末尾*/
*(a_pool->queue.tail) = a_task;
a_pool->queue.tail = &a_task->next;
a_pool->queue.cur_task_num++;
/*通知堵塞的线程*/
pthread_cond_signal(&a_pool->cond);
/*解锁*/
pthread_mutex_unlock(&a_pool->mutex);
return ;
err:
pthread_mutex_unlock(&a_pool->mutex);
free(a_task);
return -;
} void pd_pool_destroy(pd_pool_t *a_pool){
unsigned int n;
unsigned int lock; for(n = ; n < a_pool->thread_num; n++){
lock = ;
if(pd_pool_add_task(a_pool, pd_pool_exit_cb, &lock) != ){
error("pd_pool_destroy fail: add_task fail");
return;
}
while(lock){
usleep();
}
}
pthread_mutex_destroy(&a_pool->mutex);
pthread_cond_destroy(&a_pool->cond);
pthread_key_delete(key);
free(a_pool);
}
/******************************************************************************************/ void testfun(void *argv){
printf("testfun\n");
sleep();
} int main(){
pd_pool_t *a_pool = pd_pool_init(, ); pd_pool_add_task(a_pool, testfun, NULL);
pd_pool_add_task(a_pool, testfun, NULL);
pd_pool_add_task(a_pool, testfun, NULL); pd_pool_destroy(a_pool);
}
C语言实现线程池的更多相关文章
- C语言实现线程池功能
1. 线程池基本原理 2. 线程池C语言实现 2.1 线程池的数据结构 #include <stdio.h> #include <pthread.h> #include < ...
- go语言实现线程池
话说真的好久没有写博客了,最近赶新项目,工作太忙了.这一周任务比较少,又可以随便敲敲了. 逛论坛的时候突发奇想,想用go语言实现一个线程池,主要功能是:添加total个任务到线程池中,线程池开启num ...
- 用go语言实现线程池
代码放在 https://github.com/bigben0123/workerPool 安装完go软件后.执行目录中的install.cmd即可.
- C语言实现简单线程池(转-Newerth)
有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池.下面是一个C语言实现的简单的线程池. 头文件: 1: #ifndef THREAD_POOL ...
- linux下c语言实现简单----线程池
这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用.线程的优点有好多,它是"轻量级的进程",所需资源 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第5节 线程池_1_线程池的概念和原理
线程的底层原理 集合有很多种,线程池的集合用LinkedList最好
- 01 语言基础+高级:1-7 异常与多线程_day07 【线程池、Lambda表达式】
day07[线程池.Lambda表达式] 主要内容 等待与唤醒案例 线程池 Lambda表达式 教学目标 -[ ] 能够理解线程通信概念-[ ] 能够理解等待唤醒机制-[ ] 能够描述Java中线程池 ...
- Linux杂谈: 实现一种简单实用的线程池(C语言)
基本功能 1. 实现一个线程的队列,队列中的线程启动后不再释放: 2. 没有任务执行时,线程处于pending状态,等待唤醒,不占cpu: 3. 当有任务需要执行时,从线程队列中取出一个线程执行任务: ...
- github上使用C语言实现的线程池
网上介绍线程池的知识很多,但是在代码实现上介绍的又不是那么多.而且给人的一种感觉就是:你的这种实现是正规的方式还是你自己的实现? 如果有这么个疑问,且想找一个靠谱的代码拿来使用,那么这个项目是个不错的 ...
随机推荐
- [Architecture] 系统架构正交分解法
[Architecture] 系统架构正交分解法 前言 随着企业成长,支持企业业务的软件,也会越来越庞大与复杂.当系统复杂到一定程度,开发人员会发现很多系统架构的设计细节,很难有条理.有组织的用一张大 ...
- 64位win7+vs2010编译.net3.5以前的版本问题
一般编译会出现 1.“ResGen.exe”已退出,代码为2 问题处理 2.“错误 2 “LC.exe”已退出,代码为 -1. NBGIS.MainGIS” 3.“未能加载文件或程序集“ESRI.Ar ...
- MyEclipse使用心得:集成和使用Maven的方法
MyEclipse下载:http://www.myeclipsecn.com/download/ 第一步:下载和安装 1.官网下载Maven:http://maven.apache.org/downl ...
- 本周进步要点20161023(含李笑来第二场live笔记要点)
本周主要忙于去武汉参加iDOF2016智能数字油田会议,会上做了题为“油田SOA及云平台的系统思考与实践”的报告,为了准备这篇报告,用到了一些以前学过的知识,具体内容见“参加iDOF2016会议的收获 ...
- php 7.0 安装mcrypt
1. 添加ppa源 sudo add-apt-repository ppa:ondrej/php 2. 升级源 sudo apt-get update && sudo apt-get ...
- UIToolBar
//UIToolBar 是导航控制器默认隐藏的工具条 //设置UIToolBar的隐藏状态 self.navigationController.toolbarHidden = NO; //如何找到UI ...
- Android自定义View4——统计图View
1.介绍 周末在逛慕课网的时候,看到了一张学习计划报告图,详细记录了自己一周的学习情况,天天都是0节课啊!正好在学习Android自定义View,于是就想着自己去写了一个,这里先给出一张慕课网的图,和 ...
- Java异常之自定义异常
哎呀,妈呀,又出异常了!俗话说:"代码虐我千百遍,我待代码如初恋". 小Alan最近一直在忙着工作,已经很久没有写写东西来加深自己的理解了,今天来跟大家聊聊Java异常.Java异 ...
- yii2缓存的介绍和使用
作者:白狼 出处:http://www.manks.top/yii2_cache.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律 ...
- lambda表达式-转载
来源:http://www.cnblogs.com/knowledgesea/p/3163725.html 前言 1.天真热,程序员活着不易,星期天,也要顶着火辣辣的太阳,总结这些东西. 2.夸夸 ...