Linux学习——线程池的创建

news2024/11/17 0:47:05

一,线程池的作用和优点

线程池使用的是一种池化技术,当我们要使用线程时采用线程池创建就一次创建多个线程,在调用当前线程时就让其它的线程进行等待。这样做的优点有如下几点:

1,提高响应速度。线程池提前把线程创建好线程,这样能够在需要调度线程时直接调用而节省创建线程所需要的时间。

2,节省线程资源的消耗,线程池可以通过复用的方式来使用这些线程来执行一些任务。这样便可以节省一些线程资源的消耗。

3,进行统一的调度和分配,。线程是稀缺资源,线程如果被无限的创建就会导致系统的不稳定性。线程池则可以对线程进行统一的调度和分配,避免线程的无限创建。

二,线程池的创建

 1,线程池的成员

   我们实现的线程池其实就是一个类,既然是类,这个类里面就会有线程池的创建过程中所需要的一些成员。线程池中的成员如下:

1,管理线程的对象:这里采用vector数组的方式实现。

2,任务队列:线程池中的是用来解决任务的,所以我们要有一个地方来接收任务。

3,锁:在多线程并发执行时很大概率上会存在线程安全的问题,所以我们要有一个锁来保证线程安全。

4,条件变量:任务的处理和存放都是有限制的。当任务被处理完了以后便不可以再处理任务了,这个时候这个进来的线程就要等待。同样的,当任务队列堆放满了以后也不能再堆放了所以进来的线程也要等待。

代码如下:

struct TDINFO//线程的信息结构体
{
    pthread_t td;
    string name;
};

class pthreadpoll
{
private:
    vector<TDINFO> tds_;   // 管理线程的数组
    queue<T> q_;           // 任务队列
    pthread_mutex_t lock_; // 锁
    pthread_cond_t cond_;  // 条件变量
    int max_cp_;           // 任务队列的最大容量
};

2,线程池中的函数

1,构造函数

 在线程池中,这个构造函数的作用就是初始化。初始化的对象为:

1.lock_    2,cond_   

代码:

   pthreadpoll() // 构造函数,主要用于初始化锁和条件变量
    {
        pthread_mutex_init(&lock_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }

2,析构函数

析构函数的作用也很简单,就是用来对变量lock_ 和cond_进行销毁回收。这里不用对q和threads进行销毁,因为这两个时stl容器有自己的析构函数。 

代码:

​
 ~pthreadpoll()
    {
        pthread_mutex_destroy(&lock_);
        pthread_cond_destroy(&cond_);

    }

 3,开始创建线程函数

这个函数的作用便是用户通过调用这个函数来创建想要创建的对应数量的线程。

 代码如下:

 void start(int max_cp = defaultnum) // 开始创建线程
    {
        for (int i = 1; i <= max_cp; i++)
        {
            pthread_t tid;
            pthread_create(&tid, nullptr, Task, this); // 创建线程,这里的第第四个参数传入的是this指针因为是在类内,Task函数要被写成静态的
            TDINFO Td;
            string name = "thread-" + to_string(i);
            Td.name = name;
            Td.td = tid;
            tds_.push_back(Td); // 队列
        }
    }

 这里会有一个默认的数量:

const int defaultnum = 5;

这里还会有一个Task的类,代表一个任务,也就是这个线程要执行的函数

代码如下:

static void *Task(void *args)
    {
        pthreadpoll<T> *td = static_cast<pthreadpoll<T> *>(args); // 将this指针转换回来
                                                                  // 执行任务

        while (true)
        {
            // 1.先锁住
            td->Lock();
            // 2,判断当前的队列是否为空
            while (td->Isempty())
            {
                td->Sleep(); // 进入条件变量进行等待,使用while循环判断防止虚假唤醒
            }

            // 3,取任务
            T task = td->q_.front();
            td->q_.pop();
            td->Wakeup(); // 唤醒线程,唤醒下一个线程来执行任务。

            td->Unlock();
            // 4,做任务
            task.run();
            // 5,显示结果
            cout << task.Get_result() << endl;
        }
    }

在实现这个任务时要注意的点如下:

1,这个函数要实现为静态函数,因为线程创建的第三个参数的格式必须是void*(void*)形式的。如果再类内不实现为静态形式则这个函数的第一个t参数为his指针。

2,第四个参数必须传入this,因为静态函数只能调用静态成员。传入this指针以后才能调用类内的方法和成员。

 4,放入任务函数

这个函数能够让用户往任务队列里面放入任务。

代码如下:

 void push(const T &in)//外面的用户通过该函数来放入要处理的任务
    {
        q_.push(in);
        Wakeup();//唤醒线程执行任务
        sleep(1);
    }

5,拿出任务函数

该函数的任务便是拿出一个任务。

代码如下:

  T pop()
    {
        T front = q_.front();
        q_.pop();
        return front;
    }

 这个函数在Task函数中被调用。

三,线程池源码

 

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <string>
#include <queue>
#include <unistd.h>
#include "Task.hpp"
using namespace std;
const int defaultnum = 5;

struct TDINFO
{
    pthread_t td;
    string name;
};

template <class T> // 实现成模板的类
class pthreadpoll
{
public:
    void Lock() // 封装加锁
    {
        pthread_mutex_lock(&lock_);
    }

    void Unlock() // 封装解锁
    {
        pthread_mutex_unlock(&lock_);
    }

    bool Isempty()//封装队列的判空函数
    {
        return q_.empty();
    }

    void Wakeup()//封装条件变量的唤醒函数
    {
        pthread_cond_signal(&cond_);
    }

    void Sleep()//封装条件变量的等待函数
    {
        pthread_cond_wait(&cond_, &lock_);
    }

    pthreadpoll() // 构造函数,主要用于初始化锁和条件变量
    {
        pthread_mutex_init(&lock_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }

    T pop()
    {
        T front = q_.front();
        q_.pop();
        return front;
    }

    static void *Task(void *args)
    {
        pthreadpoll<T> *td = static_cast<pthreadpoll<T> *>(args); // 将this指针转换回来
                                                                  // 执行任务

        while (true)
        {
            // 1.先锁住
            td->Lock();
            // 2,判断当前的队列是否为空
            while (td->Isempty())
            {
                td->Sleep(); // 进入条件变量进行等待,使用while循环判断防止虚假唤醒
            }

            // 3,取任务
            T task = td->q_.front();
            td->q_.pop();
            td->Wakeup(); // 唤醒线程

            td->Unlock();
            // 4,做任务
            task.run();
            // 5,显示结果
            cout << task.Get_result() << endl;
        }
    }

    void start(int max_cp = defaultnum) // 开始创建线程
    {
        for (int i = 1; i <= max_cp; i++)
        {
            pthread_t tid;
            pthread_create(&tid, nullptr, Task, this); // 创建线程,这里的第第四个参数传入的是this指针因为是在类内,Task函数要被写成静态的
            TDINFO Td;
            string name = "thread-" + to_string(i);
            Td.name = name;
            Td.td = tid;
            tds_.push_back(Td); // 队列
        }
    }

    void push(const T &in)
    {
        q_.push(in);
        Wakeup();
        sleep(1);
    }

    ~pthreadpoll()
    {
        pthread_mutex_destroy(&lock_);
        pthread_cond_destroy(&cond_);
    }

private:
    vector<TDINFO> tds_;   // 管理线程的数组
    queue<T> q_;           // 任务队列
    pthread_mutex_t lock_; // 锁
    pthread_cond_t cond_;  // 条件变量
    int max_cp_;           // 任务队列的最大容量
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1522192.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Laravel框架创建项目

1.使用Composer创建项目 composer create-project --prefer-dist laravel/laravel blog "5.5.*" 如下图所以&#xff0c;Laravel框架就安装完成了 安装完成后&#xff0c;进入到项目文件夹根目录&#xff0c;打开终端&#xff0c;输入php artisan serve运行项目 p…

Linux操作系统裸机开发-环境搭建

一、配置SSH服务 1、下载安装ssh服务输入以下命令 sudo apt-get install nfs-kernel-server portmap2、建立一个供SSH服务使用的文件夹如以下命令 mkdir linux 3、完成前两步之后需要将其文件路径放到/etc/exports文件里输入以下命令&#xff1a; sudo vi /etc/esports 4.打…

天天说微服务,天天开发RESTful API,那你知道RESTful API是什么东东吗?

RESTful API&#xff08;Representational State Transfer&#xff09;是一种基于网络的架构风格&#xff0c;用于设计和构建Web服务。它是一种轻量级的架构&#xff0c;可以通过HTTP协议进行通信&#xff0c;并支持各种数据格式&#xff0c;例如JSON和XML。 在现代的Web应用程…

三极管工作原理及典型电路

一、三极管的工作原理 三极管&#xff0c;也被称为双极型晶体管或晶体三极管&#xff0c;是一种电流控制元件。主要功能是将微弱的电信号放大成幅度值较大的电信号&#xff0c;工作在饱和区和截止区时同时也被用作无触点开关。 根据结构和工作原理的不同&#xff0c;三极管可以…

Jmeter---分布式

分布式&#xff1a;多台机协作&#xff0c;以集群的方式完成测试任务&#xff0c;可以提高测试效率。 分布式架构&#xff1a;控制机&#xff08;分发任务&#xff09;与多台执行机&#xff08;执行任务&#xff09; 环境搭建&#xff1a; 不同的测试机上安装 Jmeter 配置基…

代码随想录|Day22|回溯02|216.组合总和III、17.电话号码的字母组合

216.组合总和III 本题思路和 77. 组合 类似&#xff0c;在此基础上多了一个和为 n 的判断。 class Solution:def combinationSum3(self, k: int, n: int) -> List[List[int]]:def backtrack(start, path, currentSum):# 递归终止条件&#xff1a;到达叶子节点# 如果和满足条…

HTTPS证书很贵吗?

首先&#xff0c;我们需要明确一点&#xff0c;HTTPS证书的价格并不是一成不变的&#xff0c;它受到多种因素的影响。其中最主要的因素包括证书的类型、颁发机构以及所需的验证级别。 从类型上来看&#xff0c;HTTPS证书主要分为单域名证书、多域名证书和通配符证书。单域名证书…

mmz批量多页抓取数据-AES.CBC算法-爬虫

目标&#xff1a;mmz多页下载 方法&#xff1a;加一个for循环实现多页的下载 问题&#xff1a;浏览器传输服务器时对页码参数做了加密处理 解决方法&#xff1a; 1、判断加密算法模式&#xff08;mmz是AES-CBC算法&#xff09; 2、找到加密的key和iv 代码&#xff1a; i…

基于springboot+vue实现疫情防控物资调配系统项目【项目源码】计算机毕业设计

基于springbootvue实现疫情防控物资调配系统演示 B/S结构的介绍 在确定了项目的主题和研究背景之后&#xff0c;就要确定本系统的架构了。主流的架构有两种&#xff0c;一种是B/S架构&#xff0c;一种是C/S架构。C/S的全称是Client/Server&#xff0c;Client是客户端的意思&am…

HarmonyOS NEXT应用开发—Grid和List内拖拽交换子组件位置

介绍 本示例分别通过onItemDrop()和onDrop()回调&#xff0c;实现子组件在Grid和List中的子组件位置交换。 效果图预览 使用说明&#xff1a; 拖拽Grid中子组件&#xff0c;到目标Grid子组件位置&#xff0c;进行两者位置互换。拖拽List中子组件&#xff0c;到目标List子组件…

插入排序:一种简单而有效的排序算法

插入排序&#xff1a;一种简单而有效的排序算法 一、什么是插入排序&#xff1f;二、插入排序的步骤三、插入排序的C语言实现四、插入排序的性能分析五、插入排序的优化六、总结 在我们日常生活和工作中&#xff0c;排序是一种非常常见的操作。比如&#xff0c;我们可能需要对一…

MasterPDF 强大的多功能软件

哈喽呀&#xff0c;我是苏音今天给大家带来一期免费PDF的工具&#xff0c;可以实现你的大部分需求。 最近有PDF文档相关的的需求&#xff0c;但是之前一直在用WPS&#xff0c;就看能不能实现下面两个功能 1.导出指定页的PDF 2.在某一页PDF中加入指定图片 虽然WPS可以实现将…

免费接口调用 招标信息自动抽取|招标信息|招标数据解析接口

一、开源项目介绍 一款多模态AI能力引擎&#xff0c;专注于提供自然语言处理&#xff08;NLP&#xff09;、情感分析、实体识别、图像识别与分类、OCR识别和语音识别等接口服务。该平台功能强大&#xff0c;支持本地化部署&#xff0c;并鼓励用户体验和开发者共同完善&#xf…

SpringBoot整合Seata注册到Nacos服务

项目引入pom文件 <!-- SpringCloud Seata 组件--> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-seata</artifactId><version>${alibaba.seata}</version><exclusions><exc…

Postman接口测试之断言,全网最细教程没有之一!

一、断言 在 postman 中我们是在Tests标签中编写断言&#xff0c;同时右侧封装了常用的断言&#xff0c;当然 Tests 除了可以作为断言&#xff0c;还可以当做后置处理器来编写一些后置处理代码&#xff0c;经常应用于&#xff1a; 【1】获取当前接口的响应&#xff0c;传递给…

智慧城市革命,物联网技术如何改变城市治理与生活方式

随着科技的不断进步&#xff0c;智慧城市已经成为现代城市发展的重要方向之一。物联网技术作为智慧城市的重要支撑&#xff0c;正深刻改变着城市的治理模式和居民的生活方式。本文将探讨智慧城市革命&#xff0c;以及物联网技术如何改变城市治理与生活方式&#xff0c;同时介绍…

c++入门学习⑨——STL(万字总结,超级超级详细版)看完这一篇就够了!!!

目录 &#x1f384;前言 &#x1f384;概念 引入 定义 优点 &#x1f384;六大组件 容器 算法 迭代器 仿函数 适配器 空间配置器 &#x1f384;三大组件 迭代器&#xff08;iterator&#xff09; 定义 分类&#xff1a; 正向迭代器&#xff1a; 常量正向迭代…

c语言:操作符详解(上)

目录 一、操作符的分类二、二进制和进制转换1.2进制转10进制2.10进制转2进制3.2进制转8进制4.2进制转16进制 三、原码、反码、补码四、算术操作符、-、*、/、%1.**和-**2.*3./4.% 五、移位操作符1.左移操作符2.右移操作符 六、位操作符&#xff1a;&、|、^、~七、赋值操作符…

口腔管理平台 |基于springboot框架+ Mysql+Java+B/S结构的口腔管理平台 设计与实现(可运行源码+数据库+lw文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 会员功能 系统功能设计 数据库E-R图设计 lunwen参考…

操作系统知识-操作系统作用+进程管理-嵌入式系统设计师备考笔记

0、前言 本专栏为个人备考软考嵌入式系统设计师的复习笔记&#xff0c;未经本人许可&#xff0c;请勿转载&#xff0c;如发现本笔记内容的错误还望各位不吝赐教&#xff08;笔记内容可能有误怕产生错误引导&#xff09;。 本章的主要内容见下图&#xff1a; 1、操作系统的作用…