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

[项目][WebServer][ThreadPool]详细讲解

  • 单例模式的线程安全

    • 需要双重判空指针,降低锁冲突的概率,提高性能
    • 原因1:
      • 当第一次实例化单例时,可能有多个线程同时到来,并且svr指针为空
      • 这时他们就会去竞争锁,但只有一个线程会最快拿到锁,并且成功实例化出单例对象
      • 但此时如果不加双重判空指针,那些也进了第一层if判断的,仍然会去实例化出对象
    • 原因2:
      • 为了线程安全,必然要加锁,加锁之后再去判空
      • 但每次调用GetInstance()都需要去获得锁,释放锁,效率低下
      • 此时再加一层外层if判空,这样就会避免后续调用GetInstance()时没必要的锁竞争
  • static void *ThreadRoutine(void *args)为什么要设置为static方法?

    • pthread_create传递给线程的方法只能是返回值为void*,参数为void*的函数
    • static将函数方法声明为静态方法,此时该方法没有隐含的this指针,就可以在类内把这个方法传递给线程调用了
      int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                                void *(*start_routine) (void *), void *arg);
      
  • while()防止伪唤醒

    • 可能条件变量唤醒线程时,有多个线程同时被唤醒,但是只有一个最快的线程PopTask()可以拿到任务,此时其他线程就会出错
    • while()可以在被唤醒的情况下,再次判断任务队列是否有任务
    • 这样可以保证,在某个线程醒来的时候,一定是占有互斥锁的
static const int THREAD_POOL_NUM = 10;

// 单例模式
class ThreadPool
{
public:
    static ThreadPool *GetInstance(int num = THREAD_POOL_NUM)
    {
        static pthread_mutex_t sMtx = PTHREAD_MUTEX_INITIALIZER;
        if (_tp == nullptr)
        {
            pthread_mutex_lock(&sMtx);
            if (_tp == nullptr) // 双重判断,以防线程安全问题
            {
                _tp = new ThreadPool(num);
                _tp->Init();
            }
            pthread_mutex_unlock(&sMtx);
        }

        return _tp;
    }

    // static使该成员函数没有this指针,因为线程执行的函数只能有一个void*参数
    static void *ThreadRoutine(void *args)
    {
        ThreadPool *tp = (ThreadPool *)args;

        while(true)
        {
            Task task;
            tp->Lock();
            while(tp->TaskQueueIsEmpty()) // while防止伪唤醒
            {
                tp->ThreadWait();
            }
            tp->Pop(task);
            tp->Unlock(); // 注意,不要在临界资源区内处理任务哦~
            task.ProcessOn();
        }
    }

    bool Init()
    {
        for (int i = 0; i < _num; i++)
        {
            pthread_t tid;
            if (pthread_create(&tid, nullptr, ThreadRoutine, this) != 0)
            {
                LOG(FATAL, "Create ThreadPool Error");
                return false;
            }
        }
        LOG(INFO, "Create ThreadPool Success");
        
        return true;
    }

    void Push(const Task& task) // in
    {
        Lock();
        _taskQueue.push(task); // 任务队列为临界资源,操作要加锁
        Unlock();

        ThreadWakeUp();
    }

    void Pop(Task& task) // out
    {
        task = _taskQueue.front();
        _taskQueue.pop();
    }

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

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

    bool TaskQueueIsEmpty()
    {
        return !_taskQueue.size();
    }

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

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

    bool IsStop()
    {
        return _stop;
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_cond);
    }
private:
    ThreadPool(int num = THREAD_POOL_NUM)
        : _num(num), _stop(false)
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ThreadPool(const ThreadPool &) = delete;
private:
    int _num;
    bool _stop;
    std::queue<Task> _taskQueue;
    pthread_mutex_t _mtx;
    pthread_cond_t _cond;
    static ThreadPool *_tp;
};

ThreadPool* ThreadPool::_tp = nullptr;

http://www.kler.cn/news/307939.html

相关文章:

  • 猫狗识别大模型——基于python语言
  • C# WPF中实现深拷贝的五种方式
  • 商业银行零售业务数智运营探索与应用
  • BLE 协议之物理层
  • TCP核心机制
  • 数据结构(7.3_2)——平衡二叉树
  • iOS 18 适配 Xcode 16 问题
  • 线性代数(宋浩版)(4)
  • 基于Java、SpringBoot、Vue的加油站管理系统设计
  • 【Lua学习】Lua最最基础的
  • Hugging Face NLP课程学习记录 - 0. 安装transformers库 1. Transformer 模型
  • STM32+FATFS+SD卡+RTC(生成.CSV格式文件)
  • 代码随想录_刷题笔记_第一次
  • Invoke-Maldaptive:一款针对LDAP SearchFilter的安全分析工具
  • 文生视频算法
  • SprinBoot+Vue便民医疗服务微信小程序的设计与实现
  • 基于SpringBoot+Vue+MySQL的在线视频教育平台
  • OpenGL(四) 纹理贴图
  • Linux基础---10进程管理
  • YOLOv10:深度剖析与应用前景展望
  • 文章资讯职场话题网站源码整站资源自带2000+数据
  • python之排列组合1
  • 拓扑学和低维拓扑保护
  • 其他图嵌入方法(6)
  • 鸿蒙开发入门day19-使用NDK接口构建UI(二)
  • MFC工控项目实例之十七添加手动测试界面
  • Spring Boot-Swagger相关问题
  • Docker容器技术1——docker基本操作
  • 机器学习算法与Python实战 | 概率、统计学在机器学习中应用:20个Python示例(建议收藏!)
  • 宝塔面板优化:提升服务器性能的实用指南