首页 > 系统相关 >linux线程池

linux线程池

时间:2024-11-01 10:18:13浏览次数:4  
标签:string int void linux 线程 pthread include

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

 线程池的应用场景:

* 1. 需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技 术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。 但对于长时间的任务,比如一个 Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。

* 2. 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。

* 3. 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情 况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限, 出现错误.

 线程池的种类:

* 线程池示例:

* 1. 创建固定数量线程池,循环从任务队列中获取任务对象,

* 2. 获取到任务对象后,执行任务对象中的任务接口  

代码的大概整体结构:

 

main.cc

#include "threadpool.hpp"
#include "task.hpp"

int main(){
    threadpool<task>* tp=new threadpool<task>();
    //在使用模板类时,始终需要提供具体的类型参数,这样编译器才能正确生成类型安全的代码。如果不加类型参数,将导致编译错误。
    tp->init();
    tp->start();
    int cnt=10;
    while(cnt){
        //向线程池推任务
        sleep(1);
        task t(1,1);
        tp->equeue(t);
        sleep(1);
        cout<<"cnt: "<<cnt--<<endl;
    }
    tp->stop();
    cout<<"stop!!!!!!!"<<endl;
    sleep(10);
    return 0;
}

task.hpp

#pragma once
#include<iostream>
#include<functional>
using namespace std;

class task
{
public:
    task() {}
    task(int x, int y) : _x(x), _y(y)
    {
    }
    void excute()
    {
        _result = _x + _y;
    }
    void operator()(){
        excute();
    }
    string debug()
    {
        string msg = to_string(_x) + "+" + to_string(_y) + "=?";
        return msg;
    }
    string result()
    {
        string msg = to_string(_x) + "+" + to_string(_y) +"="+ to_string(_result);
        return msg;
    }
    ~task()
    {
    }

private:
    int _x;
    int _y;
    int _result;
};

thread.hpp

#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <functional> //回调方法

using namespace std;
namespace threadmodel // 构造一个命名空间
{
    //typedef void (*func_t)(threaddate *td);
    //    typedef void (*func_t)(const string &name); // func_t 是一个指向返回类型为 void 且有参数的函数的指针。
    //     // func_t 现在可以用作一个函数指针类型的别名,表示任何指向带字符串参数且返回类型为 void 的函数的指针。
    using func_t=function<void(const string&)>;//返回值为void,参数为空的函数类型
    class thread
    {
    public:
        void excute()
        {
            cout << _name << " is running ! " << endl;
            _running = true;
            _func(_name);       // 回调不仅回调运行,他还得结束
            _running = false; // 回调完就结束了
        }

    public:
        thread(const string &name, func_t func) : _name(name), _func(func)
        {
            cout << "create: " << name << " done! " << endl;
        }
        static void *threadroutine(void *agv)          // 只要线程启动,新线程都会启动这个方法
        {                                              // 因为是类内定义的方法,所以会隐含一个this指针参数,加了static就可以,这是因为 static 成员函数不与类的实例相关联,因此它不需要 this 指针。
            thread *self = static_cast<thread *>(agv); // 获得当前对象。因为要调用_func,但_func是动态的,静态函数无法访问所以传this指针访问
            self->excute();
            return nullptr;
        }
        bool start()
        { // 线程启动方法
            int n = ::pthread_create(&_tid, nullptr, threadroutine, this);
            // 使用::pthread_create确保调用的是全局命名空间中的pthread_create函数,避免当前命名空间内可能存在的同名函数的影响。
            // 直接使用 pthread_create 会根据当前命名空间查找,如果找到了同名函数,就会调用那个函数。
            if (n != 0)
                return false;
            return true;
        }
        string status()
        {
            if (_running)
            {
                return "running";
            }
            else
                return "sleep";
        }
        void stop()
        { // 线程停止方法
            if (_running)
            {                     // 得先有线程才能停止
                _running = false; // 状态停止
                ::pthread_cancel(_tid);
                cout << _name << " stop ! " << endl;
            }
        }
        void join()
        { // 线程等待方法
            if (!_running)
            { // 没有running才值得join
                ::pthread_join(_tid, nullptr);
                cout << _name << " join ! " << endl;
            }
        }
        string threadname()
        {
            return _name;
        }
        ~thread()
        {
        }

    private:
        string _name;   // 线程的名字
        pthread_t _tid; // 线程的id
        bool _running;  // 是否处于工作状态
        func_t _func;   // 线程要执行的回调函数
    };
};

threadpool.hpp 

#pragma once
#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include "thread.hpp"

using namespace std;
using namespace threadmodel;

static const int faultnum = 5;

void test()
{
    while (true)
    {
        cout << "hello world" << endl;
        sleep(1);
    }
}

template <typename T>
class threadpool
{
private:
    void lockqueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void unlockqueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void wakeup()
    {
        pthread_cond_signal(&_cond); // 唤醒一个
    }
    void wakeupall()
    {
        pthread_cond_broadcast(&_cond); // 唤醒全部
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex); // 等待
    }
    bool isempty()
    {
        return _task_queue.empty();
    }
    void handlertask(const string &name)
    { // 每个线程都执行这个方法
        while (true)
        {
            // 拿任务
            lockqueue();
            while (isempty() && _isrunning) // 没任务并且线程不退出
            {                               // 防止伪唤醒·用while
                // 为空的任务列表,那就去休眠
                _sleep_thread_num++;
                Sleep();
                _sleep_thread_num--;
            }
            // 判定一种情况
            if (isempty() && !_isrunning)
            { // 任务队列空的并且线程池想退出
                cout << name << ": " << " quit" << endl ;
                unlockqueue();
                break;
            }
            // 有任务
            T t = _task_queue.front(); // 取任务
            _task_queue.pop();         // 老任务弹走
            unlockqueue();

            t(); // 处理任务,此处不用/不能在临界区中处理,避免浪费时间因为任务已经是你的了,你自己去处理,不占用公共资源
            cout << name << ": " << t.result() << endl;
        }
    }

public:
    threadpool(int thread_num = faultnum) : _thread_num(thread_num), _isrunning(false), _sleep_thread_num(0)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    void init()
    { // 初始化
        func_t func = bind(&threadpool::handlertask, this, placeholders::_1);
        for (int i = 0; i < _thread_num; i++)
        {
            string threadname = "thread-" + to_string(i + 1);
            _threads.emplace_back(threadname, func); // 提供名字和任务
            // emplace_back它的作用是在容器的末尾直接构造一个对象。emplace_back允许你直接传递构造对象所需的参数
        }
    }
    void start()
    { // 开始
        _isrunning = true;
        for (auto &threadd : _threads)
        {
            threadd.start();
        }
    }
    void equeue(const T &in)
    {                // 向线程池中推送任务
        lockqueue(); // 加
        if (_isrunning)//运行才可以
        {
            _task_queue.push(in);
            if (_sleep_thread_num > 0)
                wakeup(); // 唤醒
        }
        unlockqueue(); // 解
    }
    void stop()
    {
        lockqueue();
        _isrunning = false;
        wakeupall();
        unlockqueue();
    }
    ~threadpool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    int _thread_num;         // 期待有多少线程
    vector<thread> _threads; // 对象全在这里
    queue<T> _task_queue;    // 任务队列,他就是临界资源
    bool _isrunning;         // 是否运行

    int _sleep_thread_num; // 休眠的线程的个数

    pthread_mutex_t _mutex; // 对queue的锁
    pthread_cond_t _cond;   // 条件变量
};

日志:软件运行的记录信息,向显示器打印,向文件打印,特定的格式(统一格式输出) ;

格式:[日志等级][pid][filename][filenumber][time] 日志内容(支持可变参数);

日志等级:

1. DEBUG

//详细的信息,用于调试程序。包括内部状态和控制流的信息。通常在开发和测试阶段使用。

2. INFO

//一般信息,表示程序正常运行时的重要事件。例如系统启动、关闭或者某个操作成功完成等。

3. WARNING

//警告信息,表示可能会导致问题的事件。并不意味着错误,但可能需要注意的情况,例如某个功能即将过时。

4. ERROR

//错误信息,表示程序中发生了问题。这些问题会影响某个特定的功能或操作,但不会导致程序崩溃。

5. FATAL  --致命的 

//致命错误,表示程序遇到严重问题并即将停止运行。例如,关键资源不可用,无法继续执行。

标签:string,int,void,linux,线程,pthread,include
From: https://blog.csdn.net/yiqizhuashuimub/article/details/143392235

相关文章

  • 高并发IPC通信实现:HarmonyOS中的异步调用与多线程处理
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在当今的移动应用开发领域,高并发通信场......
  • Linux操作系统网站提示“Internal Server Error”报错
    可能原因及解决方法服务器资源超载解决方法:检查服务器资源使用情况,如CPU、内存和磁盘空间。如果资源使用率过高,考虑优化应用或升级服务器配置。PHP版本过低解决方法:检查当前PHP版本,并确保与WordPress兼容。可以通过以下命令查看PHP版本:   PHP文件配置错......
  • 零基础Linux入门教程:系统目录结构&文件管理命令
    Linux文件管理命令与系统目录结构1.重要文件目录根目录/(根目录)系统目录/bin:存放基本命令/sbin:存放系统管理命令/etc:系统配置文件/dev:设备文件/proc:进程和内核信息/var:易变文件,如日志/lib//lib64:共享库文件用户目录/home:用户家目录/root:......
  • 【Linux篇】常用命令及操作技巧(进阶篇 - 下)
    ......
  • 【JavaEE】【多线程】进阶知识
    目录一、常见的锁策略1.1悲观锁vs乐观锁1.2重量级锁vs轻量级锁1.3挂起等待锁vs自旋锁1.4普通互斥锁vs读写锁1.5可重入锁vs不可重入锁1.6不公平锁vs公平锁二、synchronized特性2.1synchronized的锁策略2.2synchronized加锁过程2.3其它优化措施三、......
  • 【操作系统实验课】Linux操作基础
    1.打开UbuntuUbuntu-22.04虚拟机安装-CSDN博客打开虚拟机软件启动其中的Ubuntu22.04打开Ubuntu系统终端2.创建目录和文件创建test3目录:在终端中输入命令:mkdir/test3。此命令用于在根目录下创建test3目录。(注意在命令中,“mkdir”是创建目录的命令,“/test3”是要......
  • Java多线程--Thread类的那些事3.--线程的6中状态和sleep()和 join()
      一.sleep()方法  首先在Thead类中有一个静态的sleep()方法,可以让线程进入到休眠状态即TEMD-WAITING状  在调用sleep()方法时需要注意的是在哪个线程里面调用sleep()方法,哪个线程就会进入阻塞状态.,在这个线程中的其他线程不会发生阻塞,只有当休眠时间到来这个......
  • Linux 操作系统 3 (VIM篇)
    什么是Vim?Vim是从vi发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。简单的来说,vi是老式的字处理器,不过功能已经很齐全了,但是还是有可以进步的地方。vim则可以说是程序开发者的一项很好用的工具。连vim的官方网......
  • linux cpu sys是什么占用过高
    在Linux环境中,CPU使用率是性能监控的重要组成部分。其中,sys是系统CPU时间的缩写,代表内核消耗的CPU时间。本文深入探究Linux中CPUsys使用率高的原因、影响和解决方案。通过掌握这些知识,您将更好地理解和管理Linux系统的性能。1.Linux中CPU使用率的分类在Linux中,CPU时间主要......
  • Linux基础-磁盘与磁盘分区
    硬盘与存储设备硬盘是一种计算机的存储设备,主要作用是用来存储数据,通常由一个或者多个盘片组成,既可以安装在计算机的内部,也可以外接计算机。数据的类型:操作系统,应用程序,文档多媒体文件等等计算机读取硬盘中的数据时,硬盘把数据读取到计算机的内存当中再进行处理写----->当......