当前位置: 首页 > article >正文

Linux之线程池与单例模式

目录

线程池

线程池代码

单例模式

饿汉模式单例模式

懒汉模式单例模式


在前几期,我们已经学习了多线程的创建和控制,学习了多线程中的同步和互斥,学习了多线程中的条件变量和信号量,基于此我们实现了基于阻塞队列和基于环形队列的生产者和消费者模型。本期将在此基础上进一步拓展学习,学习线程池相关的内容。

线程池

在学习线程池之前,我们通过一个场景为大家引入。图示如下。

当我们用户在用户层使用malloc函数和new操作符进行内存空间的申请时,必须由操作系统在底层使用对应的系统调用接口进行内存的申请,具体步骤为,进程由用户态切换为内核态,然后在内核态通过对应的内存算法进行内存的申请。但不免有一种情况,用户频繁的申请大小为1MB的空间,操作系统在底层不断地使用内存算法申请小块空间,在这种情景下,频繁地使用内存置换算法申请小块空间的代价是非常大的,效率也非常的低。基于此我们事先会通过操作系统在底层通过内存算法申请一大块空间,这样用户在申请时,可以直接从操作系统事先申请好的空间中去申请,不用再让操作系统频繁地使用内存算法申请小块空间,大大提高了效率。所以,内存池也是类似的原理,最终为提高了代码的执行效率。 

内存池: 提前准备好的线程,用来随时处理任务,我们就称作线程池。

线程池代码

创建一个可以处理多个任务的线程池。

ThreadPool.hpp

#pragma once
#include <queue>
#include <pthread.h>
#include <iostream>

using namespace std;

namespace threadpool
{
    const int g_num = 5;

    template <class T>
    class ThreadPool
    {
    public:
        ThreadPool(const int &num = g_num) : _num(num)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

        void Wait()
        {
            pthread_cond_wait(&_cond, &_mutex);
        }

        void Lock()
        {
            pthread_mutex_lock(&_mutex);
        }

        void Unlock()
        {
            pthread_mutex_unlock(&_mutex);
        }

        void Pop(T *out)
        {

            *out = _task_queue.front();
            _task_queue.pop();
        }

        void Push(const T &data)
        {
            Lock();
            _task_queue.push(data);
            Unlock();
            Wakeup();
        }
        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }
        static void *Rountine(void *args)
        {
            // 线程分离,分线程退出时不用主线程去等待。
            pthread_detach(pthread_self());
            ThreadPool<T> *tp = (ThreadPool<T> *)args;
               
            while (true)
            {
                 tp->Lock();
                // 分线程去处理任务
                while (tp->_task_queue.empty())
                {
                    tp->Wait();
                }
                T t;
                tp->Pop(&t);
                tp->Unlock();
                std::cout<<pthread_self()  << "得到的数据为 " << t << std::endl;
            }
        }

        void InitThreadPool()
        {
            pthread_t tid;
            for (int i = 0; i < g_num; i++)
            {
                pthread_create(&tid, nullptr, Rountine, (void *)this);
            }
        }

    private:
        // 存放任务的队列
        queue<T> _task_queue;
        // 表示线程池中线程的数目
        int _num;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;
    };

}

test.cc

#include "ThreadPool.hpp"
#include <iostream>
#include <unistd.h>
#include <time.h>
using namespace std;
using namespace threadpool;

int main()
{
    ThreadPool<int> tp;
    tp.InitThreadPool();
    // 随机数种子
    srand((long long)time(nullptr));
    while (true)
    {
        int a=rand()%20;
        tp.Push(a);
        cout << "发送的数据为" << a << endl;
        sleep(1);
    }

    return 0;
}

运行结果如下。

由运行结果可知,运行结果符合预期。 

单例模式

在学习单例模式之前,我们了解一下什么是设计模式,模式其实就是特定的场景给予特定的解决方案。在人类社会中,成熟的行业都会有成熟的设计模式。何为单例模式,单例模式其实就是一个类只允许实例化出一个对象的设计模式。

饿汉模式单例模式

饿汉就是,工资日结。

懒汉模式单例模式代码。

template <class T>
class SigDistance
{
private:
    static SigDistance<T> _t;

public:
    static SigDistance<T> *GetDistance()
    {
        return &_t;
    }
};

懒汉模式单例模式

 懒汉就是,工资月结。

template <class T>
class SigDistance
{
private:
    static SigDistance<T> *_t;
public:
    static SigDistance<T> *GetDistance()
    {
        if (_t == nullptr)
        {
            _t=new SigDistance();
        }
        return _t;
    }
};

SigDistance<T>* SigDistance<T>::_t = nullptr;

 基于懒汉单例模式的线程池

线程池往往只有一个,所以我们把线程池类设计成了单例模式,代码如下。

Thread.hpp

#pragma once
#include <queue>
#include <pthread.h>
#include <iostream>

using namespace std;

namespace threadpool
{
    const int g_num = 5;

    template <class T>
    class ThreadPool
    {
    private:
        ThreadPool<T>(const int &num = g_num) : _num(num)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }
        ~ThreadPool<T>()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

        ThreadPool<T>(const ThreadPool<T> &tp) = delete;
        ThreadPool<T> &operator=(const ThreadPool<T> &tp) = delete;
        void Wait()
        {
            pthread_cond_wait(&_cond, &_mutex);
        }

        void Lock()
        {
            pthread_mutex_lock(&_mutex);
        }

        void Unlock()
        {
            pthread_mutex_unlock(&_mutex);
        }

    public:
        void Pop(T *out)
        {

            *out = _task_queue.front();
            _task_queue.pop();
        }

        void Push(const T &data)
        {
            Lock();
            _task_queue.push(data);
            Unlock();
            Wakeup();
        }
        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }
        static ThreadPool<T> *GetDistance()
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
   
            if(_tp==nullptr)
            {
                pthread_mutex_lock(&lock);
                  if (_tp == nullptr)
                {
                    _tp = new ThreadPool<T>();
                }
            }
            _tp->InitThreadPool();
            pthread_mutex_unlock(&lock);
            return _tp;
        }
        static void *Rountine(void *args)
        {
            // 线程分离,分线程退出时不用主线程去等待。
            pthread_detach(pthread_self());
            ThreadPool<T> *tp = (ThreadPool<T> *)args;

            while (true)
            {
                tp->Lock();
                // 分线程去处理任务
                while (tp->_task_queue.empty())
                {
                    tp->Wait();
                }
                T t;
                tp->Pop(&t);
                tp->Unlock();
                std::cout << pthread_self() << "得到的数据为 " << t << std::endl;
            }
        }

        void InitThreadPool()
        {
            pthread_t tid;
            for (int i = 0; i < g_num; i++)
            {
                pthread_create(&tid, nullptr, Rountine, (void *)this);
            }
        }

    private:
        // 存放任务的队列
        queue<T> _task_queue;
        // 表示线程池中线程的数目
        int _num;
        static ThreadPool<T> *_tp;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;
    };
    template <class T>
    ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
}

需要注意的是,静态成员变量需要再类外进行初始化。 

test.cc

#include "ThreadPool.hpp"
#include <iostream>
#include <unistd.h>
#include <time.h>
using namespace std;
using namespace threadpool;

int main()
{
    ThreadPool<int> *tp = ThreadPool<int>::GetDistance();
   
    // 随机数种子
    srand((long long)time(nullptr));
    while (true)
    {
        int a = rand() % 20;
        tp->Push(a);
        cout << "发送的数据为" << a << endl;
        sleep(1);
    }

    return 0;
}

运行结果如下。

运行结果符合预期。

以上便是线程池以及单例模式的所有内容。

本期内容到此结束^_^ 

 

 


http://www.kler.cn/a/488453.html

相关文章:

  • ORB-SALM3配置流程及问题记录
  • netplan apply报错No module named ‘netifaces‘
  • 谷歌开放语音命令数据集,助力初学者踏入音频识别领域
  • 力扣刷题:二叉树OJ篇(上)
  • 【计算机网络】什么是网关(Gateway)?
  • 计算机网络 (23)IP层转发分组的过程
  • GPT-1模型详解及代码复现
  • 利用Python爬虫获取义乌购店铺所有商品列表:技术探索与实践
  • 开启Excel导航仪,跨表跳转不迷路-Excel易用宝
  • IntelliJ IDEA中Maven项目的配置、创建与导入全攻略
  • windows C#-泛型类型参数的约束详解(一)
  • 算法-盒子中小球的最大数量
  • C16.【C++ Cont】string类字符串的关系运算和与string有关的函数
  • JavaScript系列(10)-- Map数据结构专题
  • 如何确保获取的淘宝详情页数据的准确性和时效性?
  • 基于Ubuntu2404脚本搭建openstackC版-ovn网络驱动
  • 设计模式 创建型 抽象工厂模式(Abstract Factory)与 常见技术框架应用 解析
  • Win32汇编学习笔记06.APIHook
  • 单片机 期末笔记
  • 《探秘鸿蒙NEXT中的人工智能核心架构》
  • 【2025 Rust学习 --- 11 实用工具特型01】
  • 车载音频开发(二):对音频数据作音量调节
  • Java 基于微信小程序的高校科研团队管理系统设计与实现(附源码,部署,文档
  • PHP RCE
  • JS爬虫实战演练
  • js观察者模式