Linux C++线程池实例

http://www.cnblogs.com/danxi/p/6636095.html

想做一个多线程服务器测试程序,因此参考了github的一些实例,然后自己动手写了类似的代码来加深理解。

目前了解的线程池实现有2种思路:

第一种:

主进程创建一定数量的线程,并将其全部挂起,此时线程状态为idle,并将running态计数为0,等到任务可以执行了,就唤醒线程,此时线程状态为running,计数增加,如果计数达到最大线程数,就再创建一组空闲线程,等待新任务,上一组线程执行完退出,如此交替。

第二种:

采用生成者-消费者模式,主进程作为生成者,创建FIFO队列,在任务队列尾部添加任务,线程池作为消费者在队列头部取走任务执行,这之间有人会提到无锁环形队列,在单生成者单消费者的模式下是有效的,但是线程池肯定是多消费者同时去队列取任务,环形队列会造成挂死。

我的实例采用第二种方式实现,在某些应用场景下,允许一定时间内,任务排队的情况,重复利用已有线程会比较合适。

代码比较占篇幅,因此折叠在下面。

 task.h:

复制代码
 1 #ifndef TASK_H
 2 #define TASK_H
 3 
 4 #include <list>
 5 #include <pthread.h>
 6 
 7 using std::list;
 8 
 9 struct task {
10    void (*function) (void *);
11    void *arguments;
12    int id;
13 };
14 
15 struct work_queue {
16    work_queue(){
17         pthread_mutex_init(&queue_lock, NULL);
18         pthread_mutex_init(&queue_read_lock, NULL);
19         pthread_cond_init(&queue_read_cond, NULL);
20         qlen = 0;
21    }
22 
23    ~work_queue() {
24        queue.clear();
25        pthread_mutex_destroy(&queue_read_lock);
26        pthread_mutex_destroy(&queue_lock);
27        pthread_cond_destroy(&queue_read_cond);
28    }
29 
30    void push(task *tsk);
31    task *pull();
32    void post();
33    void wait();
34 
35 private:
36    int qlen;
37    list< task * > queue;
38    pthread_mutex_t queue_lock;
39    pthread_mutex_t queue_read_lock;
40    pthread_cond_t  queue_read_cond;
41 };
42 
43 #endif
复制代码

 task.cpp

复制代码
#include "task.h"void work_queue::push(task *tsk) {pthread_mutex_lock(&queue_lock);queue.push_back(tsk);qlen++;pthread_cond_signal(&queue_read_cond);pthread_mutex_unlock(&queue_lock);
}task* work_queue::pull() {wait();pthread_mutex_lock(&queue_lock);task* tsk = NULL;if (qlen > 0) {tsk = *(queue.begin());queue.pop_front();qlen--;if (qlen > 0)pthread_cond_signal(&queue_read_cond);}pthread_mutex_unlock(&queue_lock);return tsk;
}void work_queue::post() {pthread_mutex_lock(&queue_read_lock);pthread_cond_broadcast(&queue_read_cond);pthread_mutex_unlock(&queue_read_lock);
}void work_queue::wait() {pthread_mutex_lock(&queue_read_lock);pthread_cond_wait(&queue_read_cond, &queue_read_lock);pthread_mutex_unlock(&queue_read_lock);
}
复制代码

threadpool.h

复制代码
 1 #ifndef THREAD_POOL_H
 2 #define THREAD_POOL_H
 3 
 4 #include "task.h"
 5 #include <vector>
 6 
 7 using std::vector;
 8 
 9 #define safe_delete(p)  if (p) { delete p;  p = NULL; }
10 
11 struct threadpool {
12     threadpool(int size) : pool_size(size)
13                          , thread_list(size, pthread_t(0))
14                          , queue(NULL)
15                          , finish(false)
16                          , ready(0) {
17 
18         pthread_mutex_init(&pool_lock, NULL);
19     }
20 
21     ~threadpool() {
22         thread_list.clear();
23         safe_delete(queue);
24         pthread_mutex_destroy(&pool_lock);
25     }
26 
27     void init();
28     void destroy();
29     static void* thread_run(void *tp);
30 
31     void incr_ready();
32     void decr_ready();
33     bool close() const;
34     
35     work_queue *queue;
36     
37 private:
38     int pool_size;
39     int ready;
40     bool finish;
41     pthread_mutex_t pool_lock;
42     vector <pthread_t> thread_list;
43 };
44 
45 
46 #endif
复制代码

threadpool.cpp

复制代码
 1 /*
 2  * threadpool.cpp
 3  *
 4  *  Created on: 2017年3月27日
 5  *      Author: Administrator
 6  */
 7 
 8 #include "threadpool.h"
 9 
10 
11 void* threadpool::thread_run(void *tp) {
12     threadpool *pool = (threadpool *) tp;
13     pool->incr_ready();
14 
15     while(1) {
16         task* tsk = pool->queue->pull();
17         if (tsk) {
18             (tsk->function)(tsk->arguments);
19             delete tsk;
20             tsk = NULL;
21         }
22 
23         if (pool->close())
24             break;
25     }
26 
27     pool->decr_ready();
28 
29     return NULL;
30 }
31 
32 void threadpool::incr_ready() {
33     pthread_mutex_lock(&pool_lock);
34     ready++;
35     pthread_mutex_unlock(&pool_lock);
36 }
37 
38 void threadpool::decr_ready() {
39     pthread_mutex_lock(&pool_lock);
40     ready--;
41     pthread_mutex_unlock(&pool_lock);
42 }
43 
44 bool threadpool::close() const {
45     return finish;
46 }
47 
48 void threadpool::init() {
49     queue = new work_queue;
50     if (!queue) {
51         return;
52     }
53 
54     for(int i; i<pool_size; i++) {
55         pthread_create(&thread_list[i], NULL, threadpool::thread_run, (void *)this);
56     }
57 
58     while(ready != pool_size) {}
59 }
60 
61 void threadpool::destroy() {
62     finish = true;
63 
64     while(ready) {
65         if(queue) {
66             queue->post();
67         }
68     }
69 }
复制代码

main.cpp

复制代码
 1 //============================================================================
 2 // Name        : thread_pool.cpp
 3 // Author      : dancy
 4 // Version     :
 5 // Copyright   : Your copyright notice
 6 // Description : Hello World in C++, Ansi-style
 7 //============================================================================
 8 
 9 #include <iostream>
10 #include "threadpool.h"
11 #include <pthread.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 using namespace std;
16 
17 void job(void *tsk){
18     printf("job %-2d working on Thread #%u\n", ((task *)tsk)->id, (int)pthread_self());
19 }
20 
21 task *make_task(void (*func) (void *), int id) {
22     task *tsk = new task;
23     if (!tsk)
24         return NULL;
25     
26     tsk->function = func;
27     tsk->arguments = (void *)tsk;
28     tsk->id = id;
29     
30     return tsk;
31 }
32 
33 int main() {
34     threadpool tp(4);
35     tp.init();
36 
37     for(int i=0; i<40; i++) 
38         tp.queue->push(make_task(&job, i+1));
39     
40     tp.destroy();
41     printf("all task has completed\n");
42     return 0;
43 }
复制代码

 

以上代码需要在linux下编译,mingw下封装的pthread_t,多了一个void *指针,如果要适配还需要自己再封装一次。



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383803.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java编写简单的自定义异常类

除了系统中自己带的异常&#xff0c;我们也可以自己写一些简单的异常类来帮助我们处理问题。 所有的异常命名都是以Exception结尾&#xff0c;并且都是Exception的子类。 假设我们要编写一个人类的类&#xff0c;为了判断年龄的输入是否合法&#xff0c;我们编写了一个名为Il…

【Java学习笔记九】多线程

程序&#xff1a;计算机指令的集合&#xff0c;它以文件的形式存储在磁盘上&#xff0c;是应用程序执行的蓝本。 进程&#xff1a;是一个程序在其自身的地址空间中的一次执行活动。进程是资源申请、调度和独立运行的单位&#xff0c;因此&#xff0c;它使用系统中的运行资源。而…

【C++学习笔记四】运算符重载

当调用一个重载函数和重载运算符时&#xff0c;编译器通过把您所使用的参数类型和定义中的参数类型相比较&#xff0c;巨鼎选用最合适的定义。&#xff08;重载决策&#xff09; 重载运算符时带有特殊名称的函数&#xff0c;函数名是由关键字operator和其后要重载的运算符符号…

C++(纯)虚函数重写时访问权限更改问题

我们知道在Java中是自动实现多态的&#xff0c;Java中规定重写的方法的访问权限不能缩小。那么在C中我们实现多态的时候是否可以更改&#xff08;缩小&#xff09;访问权限呢&#xff1f; 经过测试&#xff0c;得到的答案如下&#xff1a;如果用基类指针指向派生类对象实现多态…

C++ — 智能指针的简单实现以及循环引用问题

http://blog.csdn.net/dawn_sf/article/details/70168930 智能指针 ____________________________________________________ 今天我们来看一个高大上的东西&#xff0c;它叫智能指针。 哇这个名字听起来都智能的不得了&#xff0c;其实等你了解它你一定会有一点失望的。。。。因…

C++开发者都应该使用的10个C++11特性

http://blog.jobbole.com/44015/ 感谢冯上&#xff08;治不好你我就不是兽医 &#xff09;的热心翻译。如果其他朋友也有不错的原创或译文&#xff0c;可以尝试推荐给伯乐在线。】 在C11新标准中&#xff0c;语言本身和标准库都增加了很多新内容&#xff0c;本文只涉及了一些皮…

shared_ptr的一些尴尬

http://blog.csdn.net/henan_lujun/article/details/8984543 shared_ptr在boost库中已经有多年了&#xff0c;C11又为其正名&#xff0c;把他引入了STL库&#xff0c;放到了std的下面&#xff0c;可见其颇有用武之地&#xff1b;但是shared_ptr是万能的吗&#xff1f;有没有什…

C++转换构造函数和类型转换函数

参考博客&#xff1a;https://blog.csdn.net/feiyanaffection/article/details/79183340 隐式类型转换 如果不同类型的数据在一起操作的时候编译器会自动进行一个数据类型转换。例如常用的基本数据类型有如下类型转换关系&#xff1a; 转换构造函数 构造函数有且仅有一个参数…

C++析构函数执行顺序

今天发现主程序中有多个对象时析构函数的执行顺序不是对象定义的顺序&#xff0c;而是对象定义顺序反过来。 思考了一下&#xff0c;结合之前继承、成员对象等的析构函数执行的顺序&#xff0c;我觉得析构函数执行的顺序为&#xff1a;构造函数的顺序反过来&#xff0c;可能是…

c++写时拷贝1

http://blog.csdn.net/SuLiJuan66/article/details/48882303 Copy On Write Copy On Write(写时复制)使用了“引用计数”&#xff08;reference counting&#xff09;&#xff0c;会有一个变量用于保存引用的数量。当第一个类构造时&#xff0c;string的构造函数会根据传入的参…

【Java学习笔记十】输入输出流

在Java.io包中提供了一系列用于处理输入/输出的流类。从功能上分为两类&#xff1a;输入流和输出流。从六结构上可分为&#xff1a;字节流&#xff08;以字节为处理单位&#xff09;和字符流&#xff08;以字符为处理单位&#xff09;。 字符是由字节组成。在Java中所有字符用…

C++ 写时拷贝 2

什么情况下会用到c中的拷贝构造函数】&#xff1a; 1&#xff09;用已经存在的同类的对象去构造出另一个新的对象 2&#xff09;当函数的形参是类的对象时&#xff0c;这时调用此函数&#xff0c;使用的是值的拷贝&#xff0c;也会调用拷贝构造函数 3&#xff09;当函数的返…

【Java学习笔记十一】图形用户界面

图形用户界面或图形用户接口(Graphical User Interface&#xff0c;GUI)是指采用图形方式,借助菜单、按钮等标准界面元素&#xff0c;用户可以通过鼠标等外设向计算机系统发出指令、启动操作&#xff0c;并将系统运行的结果同样以图形方式显示给用户的技术。 GUI是事件驱动的&…

C++ 写时拷贝 3

http://blog.csdn.net/ljianhui/article/details/22895505 字符串一种在程序中经常要使用到的数据结构&#xff0c;然而在C中却没有字符串这种类型。在C中&#xff0c;为了方便字符串的使用&#xff0c;在STL中提供了一个string类。该类维护一个char指针&#xff0c;并封装和提…

C++ String类写时拷贝 4

http://blog.51cto.com/zgw285763054/1839752 维基百科&#xff1a; 写入时复制&#xff08;英语&#xff1a;Copy-on-write&#xff0c;简称COW&#xff09;是一种计算机程序设计领域的优化策略。其核心思想是&#xff0c;如果有多个调用者&#xff08;callers&#xff09;同时…

C++笔试复习

基础知识点 C中对象数组在定义的时候全部进行实例化&#xff08;与Java不同&#xff0c;Java相当于只是定义了一个指针数组&#xff0c;没有进行实例化&#xff09; 程序的三种基本控制结构是&#xff1a;顺序结构、循环结构、选择结构 一个C程序开发步骤通常包括&#xff1a…

Java笔试复习

Java程序运行 Java程序的执行必须经过编辑、编译和运行三个步骤 编辑指编写代码&#xff0c;最终形成后缀名为.java的Java源文件编译指使用Java编译器&#xff08;javac指令&#xff09;将源文件翻译为二进制代码&#xff0c;编译后生成后缀名为.class的字节码文件&#xff0c…

Java类名与包名不区分大小写

刚才写了一个简单的Java程序&#xff0c;经过测试得到一个令人震惊的结论&#xff1a;Java类名和包名是不区分大小写的 可以看一下这个例子&#xff1a; package Test;class aBcdEfG {}class AbCdefg {}public class TTT {public static void main(String[] args){AbCdefg tm…

处理大并发之一 对epoll的理解,epoll客户端服务端代码

http://blog.csdn.net/zhuxiaoping54532/article/details/56494313处理大并发之一对epoll的理解&#xff0c;epoll客户端服务端代码序言&#xff1a;该博客是一系列的博客&#xff0c;首先从最基础的epoll说起&#xff0c;然后研究libevent源码及使用方法&#xff0c;最后研究n…

链栈基本操作

http://blog.csdn.net/jwentao01/article/details/46765517###;栈基本概念&#xff1a; 栈&#xff08;stack&#xff09;是限定在表尾进行插入和删除操作的线性表&#xff08;或单链表&#xff09;。 //只能在一段进行插入和删除&#xff0c;因此不存在&#xff0c;在中间进行…