Linux中线程池的制作

news2024/9/20 18:00:38

一.介绍

1.1概念

一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。
线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。
可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets 等的数量。

1.2应用场景

  1. 需要大量的线程来完成任务,且完成任务的时间比较短。
  2. 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
  3. 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。短时间内产生大量线程可能使内存到达极限,出现错误。

二.线程池的实现

设计一个线程池的类,用队列来实现。指定线程的数量,并提供pop与push接口。
外部线程可通过push接口将任务放入队列中,线程池中多个线程去执行pop的任务。

代码示例:

基本框架:

#define pthnums 3
template<class T>
class threadpool
{
  public:
    threadpool(int nums=pthnums)
    {
  
         pthread_num=nums;
         pthread_mutex_init(&mutex_,nullptr);
         pthread_cond_init(&cond_,nullptr);
         is_start=true;
    }
    ~threadpool()
    {
      pthread_mutex_destroy(&mutex_);
      pthread_cond_destroy(&cond_);
    }

 static void* Routine(void* argv)//类内函数有this指针,将其设置为静态,argv接受this
  {
     pthread_detach(pthread_self());
     threadpool<T> *tp = static_cast<threadpool<T>*>(argv);
     while(true)
    {
       cout<<"pthread["<<pthread_self()<<"]running"<<endl;
       sleep(1);
        tp->lockQueue();
        while(tp->isempty())
        {
          tp->waitTask();
        }
        T t=tp->pop();//拿到任务
        tp->unlockQueue();
        int one, two;
        t.get(&one, &two);
        cout<< "新线程 "<<pthread_self()<<" 完成计算任务: " << one << "+" << two << "=" << t.run() << "\n";
    }

    void start()//创建pthread_num个线程
    {
      assert(is_start);
      for(int i=0;i<pthread_num;i++)
      {
        pthread_t tid;
        pthread_create(&tid,nullptr,Routine,this);
      }
      is_start=false;
    }
  }

  private:
//封装的接口
    void lockQueue()
    {
      pthread_mutex_lock(&mutex_);
    }
    void unlockQueue()
    {
      pthread_mutex_unlock(&mutex_);
    }
    void waitTask()
    {
      pthread_cond_wait(&cond_,&mutex_);
    }
    void SignalTask()
    {
      pthread_cond_signal(&cond_);
    }
    bool isempty()
    {
      return _q.empty();
    }
    bool isFull()
    {
      return _q.size()==capacity;
    }
  private:
    queue<T> _q;
    pthread_mutex_t mutex_;//互斥锁
    pthread_cond_t cond_;//信号量
    int pthread_num;//创建线程数量
    bool is_start;
    
};

pop,push与执行任务的接口:

    void push(const T x)
    {
      lockQueue();
      _q.push(x);
      unlockQueue();
      SignalTask();
    }
  
    T pop()
    {
       T x=_q.front();
       _q.pop();
       return x;
    }

将其改为单例模式:

  ThreadPool(const ThreadPool<T> &) = delete;
  void operator=(const ThreadPool<T>&) = delete;

增加一静态成员变量,用来创建线程池,并初始为空。

  static ThreadPool<T> *instance

template <class T>
ThreadPool<T> *ThreadPool<T>::instance = nullptr;

提供一个访问单例对象的函数

 static ThreadPool<T> *getInstance()
    {
        if (nullptr == instance) //过滤重复的判断
        {
            if (nullptr == instance)
            {
                instance = new ThreadPool<T>();
            }
        }
        return instance;
    }

任务函数:完成两数相加

class Task
{
public:
  Task(int a = 10, int b = 9)
      : a_(a), b_(b)
  {
  }
  int run()
  {
    return a_ + b_;
  }
  void getTask(int *a, int *b)
  {
    *a = a_;
    *b = b_;
  }

private:
  int a_;
  int b_;
};

完整代码:

#include "Task.hpp"
#define pthnums 3
#include<unistd.h>
#include<queue>
#include<assert.h>
#include<pthread.h>
#include<iostream>
using namespace std;

template <class T>
class threadpool
{
public:
    threadpool(const threadpool<T> &) = delete;
    void operator=(const threadpool<T> &) = delete;
    static threadpool<T> *getInstance()
    {
        if (nullptr == instance) //过滤重复的判断
        {
            if (nullptr == instance)
            {
                instance = new threadpool<T>;
            }
        }
        return instance;
    }
    threadpool(int nums = pthnums)
    {
        pthread_num = nums;
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);
        is_start = true;
    }

    ~threadpool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }

    static void *Routine(void *argv) //类内函数有this指针,将其设置为静态,argv接受this
    {
        pthread_detach(pthread_self());
        threadpool<T> *tp = static_cast<threadpool<T> *>(argv);
        while (true)
        {
            cout << "pthread[" << pthread_self() << "]running" << endl;
            tp->lockQueue();
            while (tp->isempty())
            {
                tp->waitTask();
            }
            T t = tp->pop(); //拿到任务
            tp->unlockQueue();
            int one, two;
            t.get(&one, &two);
            cout << "新线程 " << pthread_self() << " 完成计算任务: " << one << "+" << two << "=" << t.run() << "\n";
        }
    }
    void start() //创建pthread_num个线程
    {
        assert(is_start);
        for (int i = 0; i < pthread_num; i++)
        {
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, this);
        }
        is_start = false;
    }
    void push(const T x)
    {
        lockQueue();
        _q.push(x);
        unlockQueue();
        SignalTask();
    }

    T pop()
    {
        T x = _q.front();
        _q.pop();
        return x;
    }

private:
    //封装的接口
    void lockQueue()
    {
        pthread_mutex_lock(&mutex_);
    }
    void unlockQueue()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void waitTask()
    {
        pthread_cond_wait(&cond_, &mutex_);
    }
    void SignalTask()
    {
        pthread_cond_signal(&cond_);
    }
    bool isempty()
    {
        return _q.empty();
    }

private:
    queue<T> _q;
    pthread_mutex_t mutex_; //互斥锁
    pthread_cond_t cond_;   //信号量
    int pthread_num;        //创建线程数量
    bool is_start;
    static threadpool<T> *instance;
};

template <class T>
threadpool<T> *threadpool<T>::instance = nullptr;

进行测试:

#include "threadpool.hpp"
#include <time.h>

int main()
{
    srand(time(nullptr));
    threadpool<Task> *p = threadpool<Task>::getInstance();
    int a;
    int b;
    p->start();
    while (true)
    {
        a = rand() % 100;
        b = rand() % 50;
        Task t(a, b);
        p->push(t);
        //sleep(1);
    }

    return 0;
}

结果:

 

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

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

相关文章

如何从github上克隆库、跑库

第一步&#xff1a;在Github上找到想要的库&#xff0c;以YOLOv3项目为例。 第二步&#xff1a;拷贝这个库到自己的电脑上&#xff0c;下载到本地。 方法一&#xff1a;在GitHub上&#xff0c;Code -> Download ZIP&#xff08;有的时候会有一些问题&#xff0c;不建议&…

DBW*的trace文件过大的bug

问题描述&#xff1a; 近期某现场发现trace目录下的dbw*文件达到了大几G的大小导致/oracle目录占用率突增&#xff0c;删除这些trace文件&#xff0c;几天后又重新生成较大的dbw*的trace 11G Dec 4 10:38 rb_dbw0_2086848.trc 3.6G Dec 4 10:38 rb_dbw1_2086852.trc 4.4G De…

前端工程师常考手写面试题指南

实现 add(1)(2)(3) 函数柯里化概念&#xff1a; 柯里化&#xff08;Currying&#xff09;是把接受多个参数的函数转变为接受一个单一参数的函数&#xff0c;并且返回接受余下的参数且返回结果的新函数的技术。 1&#xff09;粗暴版 function add (a) { return function (b) …

码云线上误删主项目文件夹的恢复

码云线上误删主项目文件夹的恢复前言描述解决办法解决问题前言描述 本来某个项目即将上线&#xff0c;然后同事不知道怎么的&#xff0c;直接打开了自己的码云&#xff0c;在网站上把主项目目录删除了。。。。是的&#xff0c;删除了&#xff01;&#xff01;&#xff01;&…

职场生涯亮红灯要注意这些

很多时候&#xff0c;当事业变红的时候&#xff0c;很多年轻人还在傻傻地工作。他们做的事情越多&#xff0c;在不被领导看重的情况下&#xff0c;就越不会得到领导的重用。在关心下属的时候&#xff0c;会在无形中释放出一些不好的信号&#xff0c;这是一种被领导抛弃的行为。…

winform 处理tabcontrol控件,隐藏顶部的tab标签,及tabcontrol的边框线

处理tabcontrol控件&#xff0c;隐藏顶部的tab标签&#xff0c;及tabcontrol的边框线处理tabcontrol控件&#xff0c;隐藏顶部的tab标签&#xff0c;及tabcontrol的边框线隐藏顶部的tab标签隐藏边框线运行效果图处理tabcontrol控件&#xff0c;隐藏顶部的tab标签&#xff0c;及…

智能电销机器人《各版本机器人部署》

科技在进步&#xff0c;时代在发展&#xff0c;越来越多人工智能产品出现在我们的生活中&#xff0c;从各种工业机器人到智能家居产品&#xff0c;人工智能在越来越多的行业出现&#xff0c;代替人们做重复枯燥的工作。在企业中出现最多的是电销机器人&#xff0c;并逐渐被越来…

【面试宝典】Mysql面试题大全

mysql面试题大全1、数据库存储引擎2、InnoDB(B树)3、TokuDB( Fractal Tree-节点带数据)4、MyIASM5、Memory6、InnoDB与MyISAM的区别7、索引8、常见索引原则有9、数据库的三范式是什么10、第一范式(1st NF - 列都是不可再分)11、第二范式(2nd NF- 每个表只描述一件事情)12、第三…

MemoryAnalyzer分析线上OOM异常

本文档记录工作中发生的一次OOM异常分析 最近线上环境频繁出现OOM异常&#xff0c;导致应用服务器宕机&#xff0c;之前有观察过最近的程序更新&#xff0c;猜测定位到最近的一个接口上&#xff0c;之前发现问题都是打印堆栈信息排查&#xff0c;但是这次发现堆栈信息并不能有…

lc刷题总结(二叉树第一次)

前中后序的递归遍历 lc144 94 145 class Solution { public:void travel(TreeNode * cur,vector<int>& vec){if(curnullptr){return;}travel(cur->left, vec);travel(cur->right, vec);vec.push_back(cur->val);}vector<int> postorderTraversal(Tre…

视频点播小程序毕业设计,视频点播系统设计与实现,微信小程序毕业设计论文怎么写毕设源码开题报告需求分析怎么做

项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于微信小程序视频点播系统&#xff0c;前台用户使用小程序&#xff0c;后台管理使用基java&#xff08;springboot框架&#xff09;msyql8数据库的B/S架构&#xff1b;通过后台添加课程信息、视频信息等&a…

Spring Cloud(十五):微服务自动化部署 DevOps CI/CD、Maven打包、ELK日志采集

DevOps CI/CD Gitlab(免费版和收费版)Jenkins基于GitLabJenkins快速实现CI\CD 后端项目打包以及部署方式 spring-boot-maven-pluginmaven-dependency-pluginmaven 官网插件maven-jar-plugin上传jar包到maven私服 ELK 日志采集 使用FileBeatLogstashES实现分布式日志收集使用 ma…

使用握手信号实现跨时钟域数据传输(verilog)

大家好&#xff0c;最近汇总了2021年oppo哲库招聘手撕代码题目&#xff0c;本文章一共含有以下几个题目&#xff1a; 一&#xff0c;使用握手信号实现跨时钟域数据传输&#xff08;verilog&#xff09; 二&#xff0c;自动售卖机&#xff08;verilog&#xff09; 三&#xf…

Jenkins执行shell脚本报错:bash: kubectl: command not found

问题描述 搭建好Jenkins之后&#xff0c;通过shell脚本构建k8s应用&#xff0c;但是脚本报错&#xff1a; bash: kubectl: command not found网上找了很多解决办法都不正确&#xff0c;并不适用于我的问题。 先说明&#xff0c;我的Jenkins和k8s各自独立的&#xff0c;不在同…

如何实现自有App上的小程序第三方微信授权登陆?

对于微信小程序来说&#xff0c;有 OpenID 或 UnionID 作为唯一标识&#xff0c;微信授权登陆小程序账号是很容易实现的&#xff0c;但对于其他应用上的小程序来说&#xff08;如支付宝、百度等&#xff09;&#xff0c;打通该登陆方式是比较麻烦的。 之前在FinClip开发了小程…

OPC Expert 最新版 Crack-2022-12-05

使用 OPC Expert 进行故障排除只是开始&#xff01;像专业人士一样解决您的 OPC 和 DCOM 连接问题&#xff01; 快速修复 OPC 和 DCOM 错误&#xff1a;使用 OPC Expert&#xff0c;您无需任何经验即可解决和修复 OPC 连接问题。OPC Expert 为您完成繁重的工作&#xff0c;以快…

excel根据颜色赋值 Excel填充颜色单元格替换成数字 excel把所有红色变成1

法/步骤 案例中&#xff0c;周一到周五产生倒班的&#xff0c;是用橙色标识的。周六周日的倒班是用蓝色标识的。然后&#xff0c;我们要将橙色的单元格替换成数字30&#xff0c;蓝色的单元格替换成数字50&#xff0c;分别代表30元和50元的倒班费。 使用快捷键CtrlH进入替换对…

如何把小程序游戏运行到自有App中?(IOS篇)

千呼万唤始出来&#xff01;FinClip 终于支持小游戏了。 我们团队算是 FinClip 的老用户了&#xff0c;年初就向官方提出了希望 FinClip 支持微信小游戏的建议。随着前段时间 “羊了个羊” 微信小游戏的爆火&#xff0c;官方也把小游戏支持提上了日程&#xff0c;近期官方开启…

[附源码]JAVA毕业设计时间管理系统(系统+LW)

[附源码]JAVA毕业设计时间管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&…

通过Node + SSE 做了一个构建日志推送

1.注册页是什么 当我们使用一个从未使用过的网站时,想要注册账号,点击注册账号时看到的网页就是注册页> 注册页例子如下: 我们看到以下的注册页中,有两大类信息: 第一大类是用户信息类,> 包括用户名,密码和email,他们都有自己的 取值规则 ,例如用户名显示不得小于3个字符…