想做一个多线程服务器测试程序,因此参考了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++线程池实例的更多相关文章

  1. java线程池实例

    目的         了解线程池的知识后,写个线程池实例,熟悉多线程开发,建议看jdk线程池源码,跟大师比,才知道差距啊O(∩_∩)O 线程池类 package thread.pool2; impor ...

  2. Java5中的线程池实例讲解

    Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活.本文通过一个网络服务器模型,来实践Java5的多线程 ...

  3. Asp.net 使用线程池实例

    实际开发经常会使用线程,如果每次使用都是创建线程.启动线程,然后销毁线程,从性能上来讲,非常占用系统开销,当线程达到一定量的时候会影响程序的运行和处理效率. 使用线程池:好处:线程池是一种多线程处理形 ...

  4. linux C 线程池(物不可穷也~)

    Linux 多线程编程之 线程池 的原理和一个简单的C实现,提高对多线程编 程的认知,同步处理等操作,以及如何在实际项目中高效的利用多线程开 发. 1.  线程池介绍 为什么需要线程池??? 目前的大 ...

  5. 线程池实例:使用Executors和ThreadPoolExecutor

    线程池负责管理工作线程,包含一个等待执行的任务队列.线程池的任务队列是一个Runnable集合,工作线程负责从任务队列中取出并执行Runnable对象. java.util.concurrent.ex ...

  6. 基于linux与线程池实现文件管理

    项目要求 1.基本 用线程池实现一个大文件夹的拷贝,大文件夹嵌套很多小文件:实现复制到指定文件夹的全部文件夹. 2.扩充功能 显示进度条:拷贝耗时统计:类似linux的tree,不能直接用system ...

  7. Linux C++线程池

    .为什么需要线程池? 部分应用程序需要执行很多细小的任务,对于每个任务都创建一个线程来完成,任务完成后销毁线程,而这就会产生一个问题:当执行的任务所需要的时间T1小于等于创建线程时间T2和销毁线程时间 ...

  8. Linux下线程池的理解与简单实现

    首先,线程池是什么?顾名思义,就是把一堆开辟好的线程放在一个池子里统一管理,就是一个线程池. 其次,为什么要用线程池,难道来一个请求给它申请一个线程,请求处理完了释放线程不行么?也行,但是如果创建线程 ...

  9. JAVA四种线程池实例

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗?   Java   1 2 3 4 5 6 7 new Thread(new Runnable() {        ...

随机推荐

  1. center os 创建用户、设置密码、修改用户、删除用户命令

    参考:https://www.linuxidc.com/Linux/2017-06/144916.htm useradd testuser  创建用户testuserpasswd testuser  ...

  2. 微信小程序已发布版本vconsole仍出现问题解决办法

    解决办法很简单,进入小程序的体验或者开发版,点击关闭调试,再次进入小程序,就不会出现了

  3. iOS之ShareSDK各社交平台申请AppKey的网址及申请流程汇总

    平台 开放平台地址 APPkey 申请流程 新浪微博 http://open.weibo.com http://bbs.mob.com/thread-89-1-4.html 新浪微博开放平台接入tip ...

  4. POJ2823 滑动窗口

    滑动最小(最大)值,模版题. 题意:给一个数列,给一个窗口大小k,顺序求每个窗口中最大值和最小值. 和挑战中的例题一模一样,就多了一个求最大,改个大于小于符号就行. 算法是利用双端队列: 以求最小值为 ...

  5. leetcode笔记(四)9. Palindrome Number

    题目描述 Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same ...

  6. SD 信贷出口 备忘

    信贷出口LVKMPFZ1,LVKMPFZ2,LVKMPFZ3

  7. [异常笔记]poi读取Excel异常

    Exception in thread "main" org.apache.poi.poifs.filesystem.OfficeXmlFileException: The sup ...

  8. is 和 isinstance的区别 and issubclass

    定义一个子类和父类 class A: pass class B(A): pass is print(type(b) is B) # 结果: True print(type(b) is A) # 结果: ...

  9. git上下载的thinkphp框架报错解决方法

    ​ git上下载的thinkphp5框架使用.gitignore没上传依赖,需要通过composer进行下载依赖,使用composer install或者composer update即可解决.

  10. shell重温---基础篇(函数操作)

        linux shell 可以用户定义函数,然后在shell脚本中可以随便调用.shell中函数的定义格式如下: [ function ] funname [()] { action; [ret ...