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语言实现的线程池
网上介绍线程池的知识很多,但是在代码实现上介绍的又不是那么多.而且给人的一种感觉就是:你的这种实现是正规的方式还是你自己的实现? 如果有这么个疑问,且想找一个靠谱的代码拿来使用,那么这个项目是个不错的 ...
随机推荐
- 《对象及DOM知识点及其应用1》
1.图片间的来回切换用if{}else{}; <超链接方式的切换图片(常用)>如:<a href="../images1/1-small.jpg" id=&quo ...
- div层调整zindex属性无效原因分析及解决方法
在做的过程中,发现了一个很简单却又很多人应该碰到的问题,设置Z-INDEX属性无效.在CSS中,只能通过代码改变层级,这个属性就是z- index,要让z-index起作用有个小小前提,就是元素的po ...
- SharePoint 2013 图文开发系列之计时器任务
SharePoint的计时器任务,又称TimerJob,由服务里的Timer服务执行,在管理中心管理,是一个类似于Windows任务计划的功能,方便定时执行一些需要的功能,以免影响服务器性能. 在Sh ...
- iOS之清除缓存
//清除缓存按钮的点击事件 - (void)putBufferBtnClicked:(UIButton *)btn{ CGFloat size = [self folderSizeAtPath:NSS ...
- IOS开发基础知识--碎片17
1:contentSize.contentInset和contentOffset区别 contentSize 是scrollview中的一个属性,它代表scrollview中的可显示区域,假如有一个s ...
- c#中抽象类(abstract)和接口(interface)的相同点与区别
相同点: 1.都可以被继承 2.都不能被实例化 3.都可以包含方法声明 4.派生类必须实现未实现的方法 区别: 1.抽象基类可以定义字段.属性.方法实现.接口只能定义属性.索引器.事件.和方法声明,不 ...
- C#中Split用法
1.用字符串分隔: using System.Text.RegularExpressions; string str="aaajsbbbjsccc"; string[] sArr ...
- Vmware虚拟机进入BIOS方法
在VMware里面如何进入BIOS是个头疼的问题,因为启动界面一闪而过(下面两个图如果不设置bios.bootDelay,基本上很难抓到),即使你狂按F2或ESC键(ESC: 调整启动顺序;F2: 进 ...
- typedef 和 #define 的区别
本文已迁移至: http://www.danfengcao.info/c/c++/2014/02/25/difference-between-define-and-typedef.html typed ...
- MYSQL的常用命令和增删改查语句和数据类型
连接命令:<a href="http://lib.csdn.net/base/mysql" class='replace_word' title="MySQL知识库 ...