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语言实现的线程池
网上介绍线程池的知识很多,但是在代码实现上介绍的又不是那么多.而且给人的一种感觉就是:你的这种实现是正规的方式还是你自己的实现? 如果有这么个疑问,且想找一个靠谱的代码拿来使用,那么这个项目是个不错的 ...
随机推荐
- java web学习总结(十二) -------------------Session
一.Session简单介绍 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下).因此,在需要保存用户数据时,服务 ...
- iOS隐私政策
隐私政策 本应用尊重并保护所有使用服务用户的个人隐私权.为了给您提供更准确.更有个性化的服务,本应用会按照本隐私权政策的规定使用和披露您的个人信息.但本应用将以高度的勤勉.审慎义务对待这些信息.除本隐 ...
- java-阻塞队列
阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列 ...
- 前端工程师如何快速的开发一个微信JSSDK应用
亲们,订阅号出来已经很久了,作为一个前端工程师或者全栈工程师,你是不是错过了什么?大概许多攻城狮同砚还没有反应过来订阅号怎么回事,就马上要被微信的应用号秀一脸了.在应用号还没有正式出来之前,我们赶紧一 ...
- 【GOF23设计模式】单例模式
来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_单例模式.应用场景.饿汉式.懒汉式 1.GOF23设计模式 2.单例模式 3.饿汉式 1 package com.t ...
- 自定义JsonResult解决 序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
接上篇的问题,给出我自己的解决方案. 同时推荐要学习MVC的可以参考下<ASP.NET MVC4 框架揭秘>. 首先,要自定义JSonResult,就要明白MVC中 JsonResult的 ...
- Android Studio安装配置、环境搭建详细步骤及基本使用
前言 Android Studio的安装配置及使用篇终于来啦~ 废话不多说,以下针对JDK正确安装(及其环境变量配置完毕,即Java开发环境下).Android Studio的安装,配置,以及创建工程 ...
- Android 手机卫士--设置界面&功能列表界面跳转逻辑处理
在<Android 手机卫士--md5加密过程>中已经实现了加密类,这里接着实现手机防盗功能 本文地址:http://www.cnblogs.com/wuyudong/p/5941959. ...
- IOS开发基础知识--碎片19
1:键盘事件顺序 UIKeyboardWillShowNotification // 键盘显示之前 UIKeyboardDidShowNotification // 键盘显示完成后 UIKeyboar ...
- iOS 系统根据导航栏和状态栏自动修改布局
问题 条件:1.有一个全屏大小的带导航的controller 2.隐藏导航栏,最顶上还会留出状态栏的位置,而不是全屏显示 解决方法 self.automaticallyAdjustsScrollVie ...