首页 > 其他分享 >项目八股[线程池]

项目八股[线程池]

时间:2023-09-09 10:22:51浏览次数:25  
标签:初始化 八股 函数 项目 mtxPool 任务 线程 pool

为什么要有线程池 因为频繁创建线程再销毁线程回收所有资源开销很大,所以项目中实现了一个线程池,线程池需要的做的事情就是维护任务队列与线程回调函数,工作线程即使在没有任务的情况下也不应该被回收,而是应该挂起等待唤醒。

所以总结一下要点:

1.线程池的实现和初始化:

1.任务如何提交打包。

2.任务队列的线程安全问题。

 

线程池这个类,在服务器程序启动之后,应该有且只有一个实例对象,因而需要以单例模式进行创建。

我在项目里使用的是懒汉式的局部静态变量实现的单例模式,局部静态变量保证了对象只有在第一次调用这个函数的时候会被初始化,之后的赋值操作都会被忽略并且它的生命周期会持续到程序的执行结束。

在C++11之前的懒汉式都会有线程安全问题创建的时候需要进行加锁,而 C++11 标准对于静态局部变量的初始化进行了互斥锁保护,保证了只有一个线程能对局部静态变量进行初始化操作其他线程再次进入时使用的都是已经初始化过的变量。而饿汉式的初始化是在程序开始的时候就进行资源的分配,不会有线程安全的问题。

线程池创建线程的时候需要让每个线程都立即执行一个回调函数并且阻塞在获取任务的为止。

 

任务如何提交打包,线程池这个类对象在初始化完成之后不应该直接被其他对象访问,应该只提供一个接口供主线程提交任务使用,将这个提交任务的函数设计成线程池的成员函数符合单一职能、和接口隔离的设计原则,不用考虑线程池内部的实现提升了封装性与安全性,也便于维护。

template<typename F>
    void addTask(F&& task)
    {
        mtxPool.lock();
        if ((int)tasks.size() < maxRequests)
        {
            //利用forward进行完美转发,保持右值引用属性
            tasks.emplace(forward<F>(task));
            condNotEmpty.signal();
        }
        mtxPool.unlock();
    }

线程池的任务提交函数时使用到了函数模板中的forward进行完美转发,保证了任务接收的参数的类型以及值都会被精准的转发给任务函数,也避免了不必要的参数拷贝,支持不同类型的任务保持了代码的简洁和可读性可维护性。

static void callback(ThreadPool* pool)
    {
        while(true)
        {
            pool->mtxPool.lock();
            while (pool->tasks.empty() && !pool->shutdown)
            {
                pool->condNotEmpty.wait(pool->mtxPool.get());
            }

            if (pool->shutdown)
            {
                pool->mtxPool.unlock();
                break;
            }
            
            //函数指针需要用move变成右值
            auto task = move(pool->tasks.front());
            pool->tasks.pop();
            pool->mtxPool.unlock();
            task(); //这里是用bind打包好的函数及其参数,可直接执行
        }
    }

回调函数里使用了move避免了从任务从任务队列里取出时进行不必要的拷贝,采用了移动构造转移了资源。类似的

 

标签:初始化,八股,函数,项目,mtxPool,任务,线程,pool
From: https://www.cnblogs.com/synapse331/p/17688975.html

相关文章

  • Vue项目中处理key=value格式的数据-demo
    要从qrCode字符串中获取expiredAt的值,你可以使用JavaScript的字符串操作方法。以下是一个示例,展示如何提取expiredAt的值:constqrCode='expiredAt=1693821037721&token=c214de74cf5847239da3005c9465025e';constparams=newURLSearchParams(qrCode);constexpiredAt=param......
  • vue项目实战之图片画廊组件的实现
    前言笔者曾经写过不少或原生的、或封装的第三方插件的组件,总结来说,并不是所有东西都用原生,自定义的才是好的。很多插件做的也是不错的。就比如笔者今天所用的这个插件:vue-awesome-swiper——这个还是很强的【轮播图】/【滚动】插件。非常的好用、方便。需要详细了解的可以去GitHu......
  • 项目认识
    项目认识能够将客户主机上面的文件自动备份到服务器上面存储起来,备份到服务器上之后客户端还要随时的通过浏览器来访问我们的服务器查看备份过的文件,同时支持下载,而且下载如果中间中断了,当前的项目还支持断点续传的功能;服务端对上传的文件进行备份存储,服务器会分辨文件是否是一个......
  • 12分钟从Executor自顶向下彻底搞懂线程池
    前言上篇文章13分钟聊聊并发包中常用同步组件并手写一个自定义同步组件聊到并发包中常用的同步组件,并且还手把手实现了自定义的同步组件本篇文章来聊聊并发包下的另一个核心-线程池阅读本文大概12分钟通读本篇文章前先来看看几个问题,看看你是否以及理解线程池什么是池化技......
  • IntelliJ IDEA新建SpringBoot项目
    IntelliJIDEA新建SpringBoot项目前言虽然新建项目比较简单,但还是有几个点需要注意。步骤下载和安装IDEA不再介绍新建工程点击“NewProject”标红的为重点关注需要关注的几个字段:Name:项目/模块名Artifact:相当于具体的功能名Group:可以理解为分组,例如......
  • uniapp项目实践总结(十三)封装文件操作方法
    导语:在日常APP开发过程中,经常要进行文件的保存、读取列表以及查看和删除文件等操作,接下来就看一下具体的方法。目录原理分析方法实现实战演练案例展示原理分析主要是以下API。uni.saveFile:保存文件到本地缓存列表;uni.getSavedFileList:获取保存文件列表;uni.getSa......
  • 27 线程池
    packageThreadDemo;importjava.lang.reflect.Executable;importjava.util.concurrent.Executor;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;//线程池publicclassTest27_Pool{publicstaticvoidmain(String[]ar......
  • vue 项目改为微应用后,原本的项目地址打不开为什么?
    当将Vue项目改为微应用之后,需要进行一些配置才能正常运行。首先,确保微应用项目的依赖中已经添加了qiankun,并在主应用的main.js中进行了相关配置。可以参考qiankun官方文档来配置主应用。在进行部署时,需要注意以下几点:跨域配置:微应用可能会存在跨域请求的问题。在部署时,需确保主应用......
  • 项目八股[日志系统]
    日志系统涉及到的C++特性语法用了一个锁+两个条件变量,跟线程池不一样只用了一个锁一个条件变量C++11提供的condition_variable类是一个同步原语,它能够阻塞一个或者多个线程,直到另一线程修改共享变量并通知condition_variable。对比POSIX的pthread_cond,pthread移植性好,condi......
  • C++多线程编程:包括多线程打印ABC、线程池实现等等
    #include<iostream>#include<thread>#include<mutex>#include<condition_variable>std::condition_variablecond;std::mutexprint_mutex;intflag=0;voidprint_thread(intnum){for(inti=0;i<10;i++)//循环{......