设为首页 加入收藏

TOP

C 实现有追求的线程池 后续(二)
2017-10-11 15:45:32 】 浏览:5718
Tags:现有 追求 线程 后续
d:%s]
" fmt "\n",\ __FILE__, __func__, __LINE__, errno, strerror(errno), ##__VA_ARGS__) #define CERR_EXIT(fmt,...) \ CERR(fmt, ##__VA_ARGS__), exit(EXIT_FAILURE) #define CERR_IF(code) \ if((code) < 0) \ CERR_EXIT(#code) // // RETURN - 打印错误信息, 并return 返回指定结果 // val : return的东西, 当需要 return void; 时候填 ',' 就过 or NIL // fmt : 双引号包裹的格式化字符串 // ... : fmt中对应的参数 // return : val // #define NIL #define RETURN(val, fmt, ...) \ do {\ CERR(fmt, ##__VA_ARGS__);\ return val;\ } while(0) #endif

##  是为了解决, 可变参数中只有一个参数的问题(... 为 empty 没有内容, GCC编译器不过).

NIL 是为了解决 return void; 语法 被 RETURN(NIL) 这种语法糖替代.

回到正题, 上面函数其实就体现了 2). pthread线程api 优化 . 主要体现在 我用 

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

来替代
  pthread_detach(pthread_self());

把线程启动运行的设置, 移动到线程外边初始化中. 意思就是创建即拥有.

降低了线程控制代码的耦合性, 微量为线程业务代码提速了.

启动慢, 运行快.  或者说不认识的时候难认识, 熟悉后好相处其实更好. O(∩_∩)O哈哈~

 

正文  -_-  详细的设计

  首先看核心结构, 每个线程对象

// 线程结构体, 每个线程一个信号量, 定点触发
struct thread {
    struct thread * next;        // 下一个线程对象
    bool wait;                   // true 表示当前线程被挂起
    pthread_t tid;               // 当前线程id
    pthread_cond_t cond;         // 线程条件变量
};

线程启动对象是一个链表. wait表示当前线程挂起状态, 用于能够快速激活挂起的线程.

// 找到空闲的线程, 并返回起信号量 
static pthread_cond_t * _threads_getcont(struct threads * pool) {
    struct thread * head = pool->thrs;
    while (head) {
        if (head->wait)
            return &head->cond;
        head = head->next;
    }
    return NULL;
}

其中 struct threads 是所有线程对象的调度结构.

// 定义线程池(线程集)定义
struct threads {
    size_t size;                // 线程池大小, 最大线程结构体数量
    size_t curr;                // 当前线程池中总的线程数
    size_t idle;                // 当前线程池中空闲的线程数
    pthread_mutex_t mutx;       // 线程互斥量
    struct thread * thrs;       // 线程结构体对象集
    struct job * head;          // 线程任务链表的链头, 队列结构
    struct job * tail;          // 线程任务队列的表尾, 后插入后执行
};

任务job采用的是一个队列结构.  线程链表同时消耗这个生产者队列.

上面wait 设计体现了 3). 在解决惊群的基础上, 更进一步, 精度定位.

 

对于第四点 4). 增加了更多的安全性代码 我们的做法体现在pthread 线程的属性控制上.

    // 设置线程属性, 设置线程 允许退出线程
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

设置开启线程取消状态, 并且支持异步取消.

    // 构建线程, 构建完毕直接获取
    if (pool->idle > 0) {
        pthread_cond_t * cond = _threads_getcont(pool);
        // 先释放锁后发送信号激活线程, 速度快, 缺点丧失线程执行优先级
        pthread_mutex_unlock(mutx);
        // 发送给空闲的线程, 这个信号量一定存在
        pthread_cond_signal(cond);
        return;
    }

定点发送信号, 精准的解决了惊群现象. 能够用空间换时间那就换, 但是不要浪费.

扯一点其它惊群, 例如在多进程中epoll中.  fork 后 epoll -> accept 只有一个成功,多个失败.

解决方案也是有的.最简单就是忽略惊群错误, 但是性能有点影响.也可以通过均衡轮询文件描述符处理.

对于本线程池相关的详细说明, 可以看下面几个源文件和测试文件

  scthreads.h

  scthreads.c

  test_scthreads.c

说道最后, 改动的主要原因是以前那版太丑了, 看不惯. 觉得美是好的, 美是一种愉悦的感受~ _φ( °-°)/

为了美怎么办, 那就整呗~

 

后记  -_-  多留点记忆吧, 说不定就忘了

  问题是难免的, 唯有打磨斟酌~

  北方的故事  http://music.163.com/#/song?id=37782112

  

  你羡慕我的心无旁骛, 我羡慕你的幸福生活

  

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇c语言遗漏梳理 下一篇c basic library framework - sim..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目