首页 > 其他分享 >半同步/半反应堆线程池

半同步/半反应堆线程池

时间:2023-02-25 17:58:51浏览次数:37  
标签:同步 函数 void queuelocker threadpool 线程 workqueue 反应堆

介绍

  • 异步线程只有一个,由主线程充当,它负责监听所有 socket 上的事件
  • 如果监听 socket 上发生读事件(有新的连接请求到来),主线程就接受得到新的连接 socket,然后往 epoll 内核事件表上注册该连接 socket 上的读写事件
  • 如果连接 socket 上发生读写事件(客户端和服务端有数据传输),主线程将该连接 socket 插入请求队列
  • 所有工作线程都睡眠在请求队列上,当有任务到来时,他们通过竞争获得任务接管权

代码

#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#include "locker.h"

// 定义成模板类是为了代码复用,T 是任务的类型
template <typename T>
class threadpool {
public:
    threadpool(int thread_number = 8, int max_requests = 10000);
    ~threadpool();
    bool append(T *request); // 往请求队列中添加任务
private:
    static void * worker(void *arg); // 工作线程运行的函数
    void run();
private:
    pthread_t *m_threads; // 描述线程池的数组
    int m_thread_number; // 线程池中的线程数
    
    std::list<T> m_workqueue; // 请求队列
    int m_max_requests; // 请求队列中允许的最大请求数
    
    locker m_queuelocker; // 保护请求队列的互斥锁
    sem m_queuestat; // 是否有任务需要处理
    
    bool m_stop; // 是否结束线程
};

template <typename T>
threadpool<T>::threadpool(int thread_number, int max_requests) : 
                          m_threads(nullptr),
                          m_thread_number(thread_number),
                          m_max_requests(max_requests),
                          m_stop(false)
{
    if (thread_number <= 0 || max_requests <= 0) {
        throw std::exception();
	}
    m_threads = new pthread_t[m_thread_number];
    if (m_threads == nullptr) {
        throw std::exception();
    }
    // 创建 m_thread_number 个线程,并将他们设置成脱离线程
    for (int i = 0; i < m_thread_number; i++) {
        printf("create the %dth thread\n", i);
        if (pthread_create(m_threads + i, nullptr, worker, (void *)this) != 0) {
            delete [] m_threads;
            throw std::exception();
        }
        if (pthread_detach(m_threads[i]) != 0) {
            delete [] m_threads;
            throw std::exception();
        }
    }
}

template <typename T>
threadpool<T>::~threadpool()
{
    delete [] m_threads;
    m_stop = true;
}

template <typename T>
bool threadpool<T>::append(T *request)
{
    m_queuelocker.lock();
    if (m_workqueue.size() > m_max_requests) {
        m_queuelocker.unlock();
        return false;
    }
    m_workqueue.push_back(request);
    m_queuelocker.unlock();
    m_queuestat.post();
    return true;
}

template <typename T>
void * threadpool<T>::worker(void *arg)
{
    threadpool *pool = (threadpool *)arg;
    pool->run();
    return pool;
}

template <typename T>
void threadpool<T>::run()
{
    while (!m_stop) {
        m_queuestat.wait();
        m_queuelocker.lock();
        if (m_workqueue.empty()) {
            m_queuelocker.unlock();
            continue;
        }
        T *request = m_workqueue.front();
        m_workqueue.pop_front();
        m_queuelocker.unlock();
        if (request == nullptr)
            continue;
        request->process(); // 任务的处理函数
    }
}

#endif

注意事项

  • 每个工作线程调用 worker 函数,worker 函数再调用 run 函数,为什么不直接 pthread_create(m_threads + i, nullptr, run, nullptr)?
    • C++ 类的非静态成员函数第一个参数是隐含的 this 指针,所以 run 函数的参数个数和所需不匹配
    • 而静态函数成员不含 this 指针
  • 如何在静态函数成员中使用类的动态成员?
    • 将类的对象作为参数传递给该静态函数,然后在静态函数中引用这个对象,并调用其动态方法
    • 通过类的静态对象来调用。比如单例模式中,静态函数可以通过类的全局唯一实例来访问动态成员函数

标签:同步,函数,void,queuelocker,threadpool,线程,workqueue,反应堆
From: https://www.cnblogs.com/cong0221/p/17154885.html

相关文章

  • 线程同步机制的封装
    #ifndefLOCKER_H#defineLOCKER_H#include<pthread.h>#include<semaphore.h>#include<exception>//封装信号量classsem{public:sem(){......
  • Java处理前端日期控制器传过来的开始时间和结束时间;程序、进程、线程、多线程是什么,为
    Java处理前端日期控制器传过来的开始时间和结束时间处理前端日期控制器传过来的开始时间和结束时间\这里其实前端可以处理的当然后台也是可以处理的总体用的方法就是JS......
  • 将采购商认证报告同步到供应商
    将采购商认证报告同步到供应商INSERTINTOmls_sup_cert_reportsup(id,--idreportData,--报告日期dr,--逻辑删除标记certStandards,--认证......
  • 【Java】ArrayList线程不安全的坑
    问题复现:使用Java的steam().paralleStream(),foreach()方法向ArrayList添加数据,导致ArrayList中出现空值,代码如下:publicstaticvoidmain(String[]args){......
  • Java多线程面试题:描述一下线程安全活跃态问题,竞态条件?
    一、线程安全活跃态问题线程因为某件事情得不到执行1、活锁线程没有阻塞,但一直重复执行某个操作,并且失败重试1)例子在消息队列中,消费者没有正确a......
  • 【多线程与高并发】- 浅谈volatile
    浅谈volatile目录浅谈volatile简介JMM概述volatile的特性1、可见性举个例子总结2、无法保证原子性举个例子分析使用volatile对原子性测试使用锁的机制总结3、禁止指令重......
  • Redis:二、jedis线程池
    中间件---Redis@目录中间件---Redis前言一、什么是jedis二、使用步骤1.Jedis读写redis数据(案例)2.编码2.1设定业务方法:2.2设定线程类,模拟用户调用:2.3设计redis......
  • Tapdata Connector 实用指南:实时数仓场景之数据实时同步至 ClickHouse
    【前言】作为中国的“Fivetran/Airbyte”,Tapdata是一个以低延迟数据移动为核心优势构建的现代数据平台,内置60+数据连接器,拥有稳定的实时采集和传输能力、秒级响应的......
  • 一文带你了解线程池原理
    一文带你了解线程池原理1.使用线程池的意义何在?​ 项目开发中,为了统一管理线程,并有效精准地进行排错,我们经常要求项目人员统一使用线程池去创建线程。因为我们是在受不......
  • mysql半同步
    什么是半同步复制所谓的半同步复制就是master主服务器每commit一个事务(简单来说就是做一个改变数据的操作),要确保slave从服务器接收完主服务器发送的binlog日志文件并写入......