Linux C++线程池实例
想做一个多线程服务器测试程序,因此参考了github的一些实例,然后自己动手写了类似的代码来加深理解。
目前了解的线程池实现有2种思路:
第一种:
主进程创建一定数量的线程,并将其全部挂起,此时线程状态为idle,并将running态计数为0,等到任务可以执行了,就唤醒线程,此时线程状态为running,计数增加,如果计数达到最大线程数,就再创建一组空闲线程,等待新任务,上一组线程执行完退出,如此交替。
第二种:
采用生成者-消费者模式,主进程作为生成者,创建FIFO队列,在任务队列尾部添加任务,线程池作为消费者在队列头部取走任务执行,这之间有人会提到无锁环形队列,在单生成者单消费者的模式下是有效的,但是线程池肯定是多消费者同时去队列取任务,环形队列会造成挂死。
我的实例采用第二种方式实现,在某些应用场景下,允许一定时间内,任务排队的情况,重复利用已有线程会比较合适。
代码比较占篇幅,因此折叠在下面。
task.h:
#ifndef TASK_H
#define TASK_H #include <list>
#include <pthread.h> using std::list; struct task {
void (*function) (void *);
void *arguments;
int id;
}; struct work_queue {
work_queue(){
pthread_mutex_init(&queue_lock, NULL);
pthread_mutex_init(&queue_read_lock, NULL);
pthread_cond_init(&queue_read_cond, NULL);
qlen = ;
} ~work_queue() {
queue.clear();
pthread_mutex_destroy(&queue_read_lock);
pthread_mutex_destroy(&queue_lock);
pthread_cond_destroy(&queue_read_cond);
} void push(task *tsk);
task *pull();
void post();
void wait(); private:
int qlen;
list< task * > queue;
pthread_mutex_t queue_lock;
pthread_mutex_t queue_read_lock;
pthread_cond_t queue_read_cond;
}; #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 > ) {
tsk = *(queue.begin());
queue.pop_front();
qlen--;
if (qlen > )
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
#ifndef THREAD_POOL_H
#define THREAD_POOL_H #include "task.h"
#include <vector> using std::vector; #define safe_delete(p) if (p) { delete p; p = NULL; } struct threadpool {
threadpool(int size) : pool_size(size)
, thread_list(size, pthread_t())
, queue(NULL)
, finish(false)
, ready() { pthread_mutex_init(&pool_lock, NULL);
} ~threadpool() {
thread_list.clear();
safe_delete(queue);
pthread_mutex_destroy(&pool_lock);
} void init();
void destroy();
static void* thread_run(void *tp); void incr_ready();
void decr_ready();
bool close() const; work_queue *queue; private:
int pool_size;
int ready;
bool finish;
pthread_mutex_t pool_lock;
vector <pthread_t> thread_list;
}; #endif
threadpool.cpp
/*
* threadpool.cpp
*
* Created on: 2017年3月27日
* Author: Administrator
*/ #include "threadpool.h" void* threadpool::thread_run(void *tp) {
threadpool *pool = (threadpool *) tp;
pool->incr_ready(); while() {
task* tsk = pool->queue->pull();
if (tsk) {
(tsk->function)(tsk->arguments);
delete tsk;
tsk = NULL;
} if (pool->close())
break;
} pool->decr_ready(); return NULL;
} void threadpool::incr_ready() {
pthread_mutex_lock(&pool_lock);
ready++;
pthread_mutex_unlock(&pool_lock);
} void threadpool::decr_ready() {
pthread_mutex_lock(&pool_lock);
ready--;
pthread_mutex_unlock(&pool_lock);
} bool threadpool::close() const {
return finish;
} void threadpool::init() {
queue = new work_queue;
if (!queue) {
return;
} for(int i; i<pool_size; i++) {
pthread_create(&thread_list[i], NULL, threadpool::thread_run, (void *)this);
} while(ready != pool_size) {}
} void threadpool::destroy() {
finish = true; while(ready) {
if(queue) {
queue->post();
}
}
}
main.cpp
//============================================================================
// Name : thread_pool.cpp
// Author : dancy
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================ #include <iostream>
#include "threadpool.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h> using namespace std; void job(void *tsk){
printf("job %-2d working on Thread #%u\n", ((task *)tsk)->id, (int)pthread_self());
} task *make_task(void (*func) (void *), int id) {
task *tsk = new task;
if (!tsk)
return NULL; tsk->function = func;
tsk->arguments = (void *)tsk;
tsk->id = id; return tsk;
} int main() {
threadpool tp();
tp.init(); for(int i=; i<; i++)
tp.queue->push(make_task(&job, i+)); tp.destroy();
printf("all task has completed\n");
return ;
}
以上代码需要在linux下编译,mingw下封装的pthread_t,多了一个void *指针,如果要适配还需要自己再封装一次。
Linux C++线程池实例的更多相关文章
- java线程池实例
目的 了解线程池的知识后,写个线程池实例,熟悉多线程开发,建议看jdk线程池源码,跟大师比,才知道差距啊O(∩_∩)O 线程池类 package thread.pool2; impor ...
- Java5中的线程池实例讲解
Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活.本文通过一个网络服务器模型,来实践Java5的多线程 ...
- Asp.net 使用线程池实例
实际开发经常会使用线程,如果每次使用都是创建线程.启动线程,然后销毁线程,从性能上来讲,非常占用系统开销,当线程达到一定量的时候会影响程序的运行和处理效率. 使用线程池:好处:线程池是一种多线程处理形 ...
- linux C 线程池(物不可穷也~)
Linux 多线程编程之 线程池 的原理和一个简单的C实现,提高对多线程编 程的认知,同步处理等操作,以及如何在实际项目中高效的利用多线程开 发. 1. 线程池介绍 为什么需要线程池??? 目前的大 ...
- 线程池实例:使用Executors和ThreadPoolExecutor
线程池负责管理工作线程,包含一个等待执行的任务队列.线程池的任务队列是一个Runnable集合,工作线程负责从任务队列中取出并执行Runnable对象. java.util.concurrent.ex ...
- 基于linux与线程池实现文件管理
项目要求 1.基本 用线程池实现一个大文件夹的拷贝,大文件夹嵌套很多小文件:实现复制到指定文件夹的全部文件夹. 2.扩充功能 显示进度条:拷贝耗时统计:类似linux的tree,不能直接用system ...
- Linux C++线程池
.为什么需要线程池? 部分应用程序需要执行很多细小的任务,对于每个任务都创建一个线程来完成,任务完成后销毁线程,而这就会产生一个问题:当执行的任务所需要的时间T1小于等于创建线程时间T2和销毁线程时间 ...
- Linux下线程池的理解与简单实现
首先,线程池是什么?顾名思义,就是把一堆开辟好的线程放在一个池子里统一管理,就是一个线程池. 其次,为什么要用线程池,难道来一个请求给它申请一个线程,请求处理完了释放线程不行么?也行,但是如果创建线程 ...
- JAVA四种线程池实例
1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java 1 2 3 4 5 6 7 new Thread(new Runnable() { ...
随机推荐
- web常用软件
编辑器: VSCode HBuilder WebStorm NotePad++ Eclipse Atom 常用插件: SwitchyOmega Vue-Tools server类: tomcat Ng ...
- LeetCode 简单 - 最大子序和(53)
采用动态规划方法O(n) 设sum[i]为以第i个元素结尾且和最大的连续子数组.假设对于元素i,所有以它前面的元素结尾的子数组的长度都已经求得,那么以第i个元素结尾且和最大的连续子数组实际上,要么是以 ...
- atan和atan2反正切计算
typedef struct point { double x, y; }point; //给定两个点 point a(x1,y1),b(x2,y2); 使用反三角函数atan求斜率,原型如下 flo ...
- chromium之tuple
// A Tuple is a generic templatized container, similar in concept to std::pair. // There are classes ...
- oracle 12.1.0.2中对象锁对系统的较大影响
环境:oracle 12.1.0.2 rac ,4节点 一.概述 通常来说,如果是oltp应用,那么部署在rac上,是不错的注意. 但实现情况中,往往是混合类型,既有OLTP也有OLAP. 如果没有 ...
- HDFS的存储策略
本文介绍hdfs的存储策略 内容译自:http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-hdfs/ArchivalStor ...
- python 面向对象类与类之间的关系
主要内容: 1. 依赖关系 2. 关联关系, 组合关系, 聚合关系 3. 继承关系 4. 类中的特殊成员 引子 大千世界, 万物之间皆有规则和规律,我们的类和对象是对大千世界中的所有事物进行归类. 那 ...
- 【原创】从 列表的重复 到 用sum展开二层嵌套列表将子元素合并
转载请注明出处:https://www.cnblogs.com/oceanicstar/p/9517159.html ★像R语言里头有rep函数可以让向量的值重复,在python里面可以直 ...
- Mina 组件介绍之 IoAcceptor 与 IoConnector
在网络通信中,Socket通信的双方分为服务端与客户端,在Java NIO 的实现中采用Socket/ServerSocket, SocketChannel/ServerSocketChannel分别 ...
- laydate js动态添加时间
$("#test2").click(function(){ var input=$('<input/>'); $("#test1").append( ...