线程池介绍(普通与单例版本)

线程池

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

应用场景

  1. 需要大量的线程来完成任务,且完成任务的时间比较短。WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。但对于长时间的任务,比如一个Telnet连接请求,线程池的优势就不明显了。因为Telnet会话时间比线程创建时间大多了。
  2. 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
  3. 接收突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量用户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存达到极限,出现错误。

示例

thread_pool.hpp

#pragma once

#include <iostream>
#include <unistd.h>
#include <queue>
#include <string>
#include <pthread.h>

namespace ns_thread_pool
{
    const int g_num = 5;

    template <class T>
    class ThreadPool
    {
    private:
        int _num;
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;
        std::queue<T> _tq; //临界资源

    public:
        void Lock()
        {
            pthread_mutex_lock(&_mtx);
        }

        void UnLock()
        {
            pthread_mutex_unlock(&_mtx);
        }

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

        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }

        bool IsEmpty()
        {
            return _tq.empty();
        }

    public:
        ThreadPool(int num = g_num)
        : _num(num)
        {
            pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }

        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }

        static void *Routine(void *arg) //类内函数自带this指针,故使用static
        {
            pthread_detach(pthread_self());
            ThreadPool<T> *tp = (ThreadPool<T>*)arg;

            while (true)
            {
                tp->Lock();
                while (tp->IsEmpty())
                {
                    tp->Wait();
                }
                T task;
                tp->Pop(&task);

                tp->UnLock();
                task();
            }

        }

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

        void Push(const T& in)
        {
            Lock();
            _tq.push(in);
            UnLock();
            Wakeup();
        }

        void Pop(T *out)
        {
            *out = _tq.front();
            _tq.pop();
        }

    };
}

main.cc

#include "thread_pool.hpp"
#include "Task.hpp"

#include <iostream>
#include <unistd.h>
#include <time.h>

using namespace ns_task;
using namespace ns_thread_pool;

int main()
{
    srand((long long)time(nullptr));
    ThreadPool<Task> *tp = new ThreadPool<Task>();
    tp->InitThreadPool();
    while (true)
    {
        int x = rand() % 20 + 1;
        int y = rand() % 10 + 1;
        char op = ops[rand() % 5];
        Task t(x, y, op);
        tp->Push(t);
        std::cout << "插入任务:" << x << op << y << "=?" << std::endl;
        sleep(1);
    }
    return 0;
}

Task.hpp

#pragma once

#include <iostream>
#include <pthread.h>
#include <string>

namespace ns_task
{
    std::string ops = "+-*/%";

    class Task
    {
    private:
        int _x;
        int _y;
        char _op;

    public:
        Task() {}
        Task(int x, int y, char op)
        : _x(x)
        , _y(y)
        , _op(op)
        {}

        int Run()
        {
            int res = 0;
            switch(_op)
            {
                case '+':
                    res = _x + _y;
                    break;
                case '-':
                    res = _x - _y;
                    break;
                case '*':
                    res = _x * _y;
                    break;
                case '/':
                    res = _x / _y;
                    break;
                case '%':
                    res = _x % _y;
                    break;
                default:
                    std::cout << "no such op" << std::endl;
                    break;
            }
            std::cout << pthread_self() << "is dealing with " << _x << _op << _y << "=" << res << std::endl;
            return res;
        }

        int operator()()
        {
            return Run();
        }

        ~Task()
        {}
    };
}

单例模式

某些类,之应该具有一个对象(实例),就称之为单例。在很多服务器开发场景中,经常需要让服务器加载很多的数据到内存中,此时往往要用一个单例的类来管理这些数据。

饿汉实现方式和懒汉实现方式

饿汉方式:吃完饭,立刻洗碗,这样下一顿吃的时候立刻那碗吃饭
懒汉方式:等到下一顿再洗碗

懒汉方式的核心思想是“延时加载”,从而优化服务器的启动速度。

thread_pool.hpp

#pragma once

#include <iostream>
#include <unistd.h>
#include <queue>
#include <string>
#include <pthread.h>

namespace ns_thread_pool
{
    const int g_num = 5;

    template <class T>
    class ThreadPool
    {
    private:
        int _num;
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;
        std::queue<T> _tq; //临界资源
        static ThreadPool<T> *ins;

    private:
        ThreadPool(int num = g_num)
        : _num(num)
        {
            pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }

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

    public:
        void Lock()
        {
            pthread_mutex_lock(&_mtx);
        }

        void UnLock()
        {
            pthread_mutex_unlock(&_mtx);
        }

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

        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }

        bool IsEmpty()
        {
            return _tq.empty();
        }

    public:
        static ThreadPool<T>* GetInstance(const int num = g_num)
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
            if (ins == nullptr)
            {
                pthread_mutex_lock(&lock);
                if (ins == nullptr)
                {
                    std::cout << "首次调用" << std::endl;
                    ins = new ThreadPool<T>(num);
                    ins->InitThreadPool();
                }
                pthread_mutex_unlock(&lock);
            }
            return ins;
        }

        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }

        static void *Routine(void *arg) //类内函数自带this指针,故使用static
        {
            pthread_detach(pthread_self());
            ThreadPool<T> *tp = (ThreadPool<T>*)arg;

            while (true)
            {
                tp->Lock();
                while (tp->IsEmpty())
                {
                    tp->Wait();
                }
                T task;
                tp->Pop(&task);

                tp->UnLock();
                task();
            }

        }

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

        void Push(const T& in)
        {
            Lock();
            _tq.push(in);
            UnLock();
            Wakeup();
        }

        void Pop(T *out)
        {
            *out = _tq.front();
            _tq.pop();
        }

    };

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

}

main.cc

#include "thread_pool.hpp"
#include "Task.hpp"

#include <iostream>
#include <unistd.h>
#include <time.h>

using namespace ns_task;
using namespace ns_thread_pool;

int main()
{
    srand((long long)time(nullptr));
    while (true)
    {
        int x = rand() % 20 + 1;
        int y = rand() % 10 + 1;
        char op = ops[rand() % 5];
        Task t(x, y, op);
        ThreadPool<Task>::GetInstance()->Push(t);
        std::cout << "插入任务:" << x << op << y << "=?" << ThreadPool<Task>::GetInstance() << std::endl;
        sleep(1);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JayceSun449

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值