设为首页 加入收藏

TOP

C 实现有追求的线程池 后续(一)
2017-10-11 15:45:32 】 浏览:5714
Tags:现有 追求 线程 后续

引言  -_-  还是老套路开局

  很久以前写过一个有追求的线程池 -> C 实现有追求的线程池 探究

讲述的是一种思路, 并且实现了. 可以一用. 最近在详细搞simplec 框架. 准备发布个正式版.

刚好顺带优化一下这个线程池.优化的结果有如下几个方面.

  1). 更加美观合理的api

  2). pthread线程api 优化

  3). 在解决惊群的基础上, 更进一步, 精度定位.

  4). 增加了更多的安全性代码

  扯淡一点, 线程池对于历史语言C, C++中应用的场景并不多. 可以用线程解决的, 都可以用消息队列解决.

当然线程有个不一样的属性就是可抢占性. 当你追求性能的时候, 那么这个基本满足不了.

至少现代的游戏框架设计中抢占式任务没见有这个必要.

  以下容许我分段阐述思路, scthreads.h

#ifndef _H_SIMPLEC_SCTHREADS
#define _H_SIMPLEC_SCTHREADS

#include <schead.h>

//
// 这是个线程池的库. 支持异步取消 也加过一些线程帮助库
//

typedef struct threads * threads_t;

//
// async_run - 开启一个自销毁的线程 运行 run
// run        : 运行的主体
// arg        : run的参数
// return     : >= Success_Base 表示成功
//
extern int async_run(die_f run, void * arg);

//
// threads_create - 创建一个线程池处理对象
// return    : 返回创建好的线程池对象, NULL表示失败
//
extern threads_t threads_create(void);

//
// threads_delete - 异步销毁一个线程池对象
// pool        : 线程池对象
// return      : void
//
extern void threads_delete(threads_t pool);

//
// threads_add - 线程池中添加要处理的任务
// pool        : 线程池对象
// run         : 运行的执行题
// arg         : run的参数
// return      : void
//
extern void threads_add(threads_t pool, die_f run, void * arg);

#endif // !_H_SIMPLEC_SCTHREADS

通过上面 可以说明 1). 更加美观合理的api 因为内部使用宏来确定最优线程数. 不需要玩家自己指定.当然这个数值偏小.

 

前言  -_-  来点开胃点心

  有时候我们使用pthread 线程的时候, 步骤有点小繁琐. 我们其实不太需要知道有这个线程, 这个线程执行完毕之后做什么.

只希望简单的帮我异步的执行一个方法就可以了. 这里设计了 thread_run 函数.

typedef void    (* die_f)(void * node);
extern int async_run(die_f run, void * arg);

详细的设计套路. 如下

#include <pthread.h>

// 运行的主体
struct func {
    die_f run;
    void * arg;
};

// thread_run 中 pthread 执行的实体
static void * _run(void * arg) {
    struct func * func = arg;
    func->run(func->arg);
    free(arg);
    return NULL;
}

//
// async - 开启一个自销毁的线程 运行 run
// run        : 运行的主体
// arg        : run的参数
// return     : >= Success_Base 表示成功
//
int 
async_run(die_f run, void * arg) {
    pthread_t tid;
    pthread_attr_t attr;
    struct func * func = malloc(sizeof(struct func));
    if (NULL == func)
        RETURN(Error_Alloc, "malloc sizeof(struct func) is error");

    func->run = run;
    func->arg = arg;

    // 构建pthread 线程奔跑起来
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    if (pthread_create(&tid, &attr, _run, func) < 0) {
        free(func);
        pthread_attr_destroy(&attr);
        RETURN(Error_Base, "pthread_create error run, arg = %p | %p.", run, arg);
    }

    pthread_attr_destroy(&attr);
    return Success_Base;
}

这里扯一点, 第一个是我常用的通用错误枚举. 

//
// flag_e - 全局操作基本行为返回的枚举, 用于判断返回值状态的状态码
// >= 0 标识 Success状态, < 0 标识 Error状态
//
typedef enum {
    Success_Exist    = +2,            //希望存在,设置之前已经存在了.
    Success_Close    = +1,            //文件描述符读取关闭, 读取完毕也会返回这个
    Success_Base     = +0,            //结果正确的返回宏

    Error_Base       = -1,            //错误基类型, 所有错误都可用它, 在不清楚的情况下
    Error_Param      = -2,            //调用的参数错误
    Error_Alloc      = -3,            //内存分配错误
    Error_Fd         = -4,            //文件打开失败
    Error_TOUT       = -5,            //超时错误
} flag_e;

项目实战中运用的很好. 基本一个函数返回的错误就那些.

再扯第二点. 在我们使用 pthread_attr_init的时候posix线程推荐我们立即也必须调用 pthread_attr_destroy.

保证你自己的东西自己释放. 实际上 pthread_*_destroy 这类函数只是返回当前线程状态, 不涉及资源销毁内容.

再扯第三点, 好用的RETURN宏, 还是挺飘的.

// 
// 控制台输出完整的消息提示信息, 其中fmt必须是 "" 包裹的字符串
// CERR           -> 简单的消息打印
// CERR_EXIT      -> 输出错误信息, 并推出当前进程
// CERR_IF        -> if语句检查, 如果符合标准错误直接退出
// 
#ifndef _H_CERR
#define _H_CERR

#define CERR(fmt, ...) \
    fprintf(stderr, "[%s:%s:%d][errno %
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇c语言遗漏梳理 下一篇c basic library framework - sim..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目