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

【Linux】多线程_9

文章目录

  • 九、多线程
    • 10. 线程池
  • 未完待续


九、多线程

10. 线程池

这里我没实现一些 懒汉单例模式 的线程池,并且包含 日志打印 的线程池:
Makefile

threadpool:Main.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f threadpool

Thread.hpp

#ifndef __THREAD_HPP__
#define __THREAD_HPP__#include <iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <pthread.h>namespace ThreadModule
{// 类型别名using func_t = std::function<void(std::string)>;// 线程类class Thread{public:void Excute(){_func(_threadname);}public:Thread(func_t func, std::string name = "none-name"):_func(func),_threadname(name),_stop(true){}// 执行任务static void *threadroutine(void *args){Thread *self = static_cast<Thread*>(args);self->Excute();return nullptr;}// 启动线程bool Start(){int n = pthread_create(&_tid, nullptr, threadroutine, this);if(!n){_stop = false;return true;}else{return false;}}// 停止线程void Detach(){if(!_stop){pthread_detach(_tid);}}// 等待线程结束void Join(){if(!_stop){pthread_join(_tid, nullptr);}}std::string name(){return _threadname;}void Stop(){_stop = true;}~Thread(){}private:pthread_t _tid;std::string _threadname;func_t _func;bool _stop;};
}#endif

LockGuard.hpp

#ifndef __LOCK_GUARD_HPP__
#define __LOCK_GUARD_HPP__#include <iostream>
#include <pthread.h>class LockGuard
{
public:// 构造函数加锁LockGuard(pthread_mutex_t *mutex):_mutex(mutex){pthread_mutex_lock(_mutex);}// 析构函数解锁~LockGuard(){pthread_mutex_unlock(_mutex);}
private:pthread_mutex_t *_mutex;
};#endif

Log.hpp

#pragma once#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include "LockGuard.hpp"// 宏定义,用于定义日志格式
#define LOG(level, format, ...) do{LogMessage(__FILE__, __LINE__, gIsSave, level, format, ##__VA_ARGS__);}while (0)
// 将日志输入到文件
#define EnableFile() do{gIsSave = true;}while (0)
// 将日志输出到显示器
#define EnableScreen() do{gIsSave = false;}while (0)bool gIsSave = false;
// 日志文件名
const std::string logname = "log.txt";// 枚举日志级别
enum Level
{DEBUG = 0,INFO,WARNING,ERROR,FATAL
};// 保存日志到文件
void SaveFile(const std::string &filename, const std::string &message)
{std::ofstream out(filename, std::ios::app);if (!out.is_open()){return;}out << message;out.close();
}// 日志级别转字符串
std::string LevelToString(int level)
{switch (level){case DEBUG:return "Debug";case INFO:return "Info";case WARNING:return "Warning";case ERROR:return "Error";case FATAL:return "Fatal";default:return "Unknown";}
}// 获取当前时间字符串
std::string GetTimeString()
{time_t curr_time = time(nullptr);struct tm *format_time = localtime(&curr_time);if (format_time == nullptr)return "None";char time_buffer[1024];snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",format_time->tm_year + 1900,format_time->tm_mon + 1,format_time->tm_mday,format_time->tm_hour,format_time->tm_min,format_time->tm_sec);return time_buffer;
}// 日志锁,同一时刻只能写一个日志
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;// 日志信息
void LogMessage(std::string filename, int line, bool issave, int level, const char *format, ...)
{// 日志级别std::string levelstr = LevelToString(level);// 时间std::string timestr = GetTimeString();// 进程idpid_t selfid = getpid();// 日志内容char buffer[1024];va_list arg;va_start(arg, format);vsnprintf(buffer, sizeof(buffer), format, arg);va_end(arg);// 日志格式化std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +"[" + std::to_string(selfid) + "]" +"[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";LockGuard lockguard(&lock);// 输出日志if (!issave){std::cout << message;}else{SaveFile(logname, message);}
}

Task.hpp

#pragma once#include <iostream>
#include <string>
#include <functional>class Task
{
public:Task(){}Task(int a, int b):_a(a),_b(b),_result(0){}// 执行加法功能void Excute(){_result = _a + _b;}// 结果std::string ResultToString(){return std::to_string(_a) + "+" + std::to_string(_b) + "=" + std::to_string(_result);}// 问题std::string DebugToString(){return std::to_string(_a) + "+" + std::to_string(_b) + "= ?";}// 重载()运算符void operator()(){Excute();}
private:int _a;int _b;int _result;
};

ThreadPool.hpp

#pragma once#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"using namespace ThreadModule;// 线程池默认线程数
const static int gdefaultthreadnum = 10;template <typename T>
class ThreadPool
{
private:// 线程互斥锁void LockQueue(){pthread_mutex_lock(&_mutex);}// 线程互斥解锁void UnlockQueue(){pthread_mutex_unlock(&_mutex);}// 线程等待void ThreadSleep(){pthread_cond_wait(&_cond, &_mutex);}// 线程唤醒void ThreadWakeup(){pthread_cond_signal(&_cond);}// 唤醒全部线程void ThreadWakeupAll(){pthread_cond_broadcast(&_cond);}// 私有构造函数ThreadPool(int threadnum = gdefaultthreadnum):_threadnum(threadnum),_waitnum(0),_isrunning(false){// 初始化锁pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);// 日志LOG(INFO, "ThreadPool Construct()");}// 初始化线程池void InitThreadPool(){// 创建一批线程for (int num = 0; num < _threadnum; num++){std::string name = "thread-" + std::to_string(num + 1);_threads.emplace_back(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1), name);// 日志LOG(INFO, "init thread %s done", name.c_str());}_isrunning = true;}// 启动线程池void Start(){for (auto &thread : _threads){thread.Start();}}// 任务处理函数void HandlerTask(std::string name) // 类的成员方法,也可以成为另一个类的回调方法,方便我们继续类级别的互相调用!{// 日志LOG(INFO, "%s is running...", name.c_str());while (true){// 加锁LockQueue();while (_task_queue.empty() && _isrunning){_waitnum++;ThreadSleep();_waitnum--;}// 退出情况if (_task_queue.empty() && !_isrunning){UnlockQueue();break;}// 取出任务T t = _task_queue.front();_task_queue.pop();UnlockQueue();// 日志LOG(DEBUG, "%s get a task", name.c_str());// 执行任务t();// 日志LOG(DEBUG, "%s handler a task, result is: %s", name.c_str(), t.ResultToString().c_str());}}// 禁用拷贝构造和赋值操作ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;ThreadPool(const ThreadPool<T> &) = delete;
public:static ThreadPool<T> *GetInstance(){// 首次使用时,创建线程池单例if (nullptr == _instance){// 对于多线程创建单例时加锁,保证线程安全LockGuard lockguard(&_lock);if (nullptr == _instance){// 创建线程池实例_instance = new ThreadPool<T>();_instance->InitThreadPool();_instance->Start();LOG(DEBUG, "创建线程池单例");return _instance;}}// 已经创建过线程池单例,直接返回LOG(DEBUG, "获取线程池单例");return _instance;}// 停止线程池void Stop(){LockQueue();_isrunning = false;ThreadWakeupAll();UnlockQueue();}// 等待线程池退出void Wait(){for (auto &thread : _threads){thread.Join();LOG(INFO, "%s is quit...", thread.name().c_str());}}// 向线程池中添加任务bool Enqueue(const T &t){bool ret = false;LockQueue();if (_isrunning){_task_queue.push(t);if (_waitnum > 0){ThreadWakeup();}LOG(DEBUG, "enqueue task success");ret = true;}UnlockQueue();return ret;}// 析构自动释放锁资源~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}
private:// 线程池中线程个数int _threadnum;// 线程std::vector<Thread> _threads;// 任务队列std::queue<T> _task_queue;// 互斥锁pthread_mutex_t _mutex;// 条件变量pthread_cond_t _cond;// 等待线程数int _waitnum;// 线程池是否运行bool _isrunning;// 线程池单例static ThreadPool<T> *_instance;// 全局锁static pthread_mutex_t _lock;
};// 初始化静态变量
template <typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;// 全局锁
template <typename T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;

Main.cc

#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Log.hpp"
#include <iostream>
#include <string>
#include <memory>
#include <ctime>int main()
{// 日志LOG(DEBUG, "程序已经加载");sleep(2);// 创建线程池单例ThreadPool<Task>::GetInstance();sleep(2);// 获取单例ThreadPool<Task>::GetInstance();sleep(2);ThreadPool<Task>::GetInstance();sleep(2);ThreadPool<Task>::GetInstance();sleep(2);// 等待线程结束ThreadPool<Task>::GetInstance()->Wait();sleep(2);return 0;
}

结果演示:
在这里插入图片描述


未完待续

相关文章:

【Linux】多线程_9

文章目录 九、多线程10. 线程池 未完待续 九、多线程 10. 线程池 这里我没实现一些 懒汉单例模式 的线程池&#xff0c;并且包含 日志打印 的线程池&#xff1a; Makefile&#xff1a; threadpool:Main.ccg -o $ $^ -stdc11 -lpthread .PHONY:clean clean:rm -f threadpoolT…...

LabVIEW设备检修信息管理系统

开发了基于LabVIEW设计平台开发的设备检修信息管理系统。该系统应用于各种设备的检修基地&#xff0c;通过与基地管理信息系统的连接和数据交换&#xff0c;实现了本地检修工位数据的远程自动化管理&#xff0c;提高了设备的检修效率和安全性。 项目背景 现代设备运维过程中信…...

python爬虫基础:使用lxml库进行HTML解析和数据提取的实践指南

使用lxml库进行HTML解析和数据提取的实践指南 在Python编程中&#xff0c;网页抓取和数据提取是一项常见任务。lxml库因其高效性和强大的XPath支持&#xff0c;成为了处理HTML和XML文档的优选工具。本文将带你了解如何使用lxml来解析HTML文档并提取所需数据。 1. 安装lxml库 …...

大语言模型系列:Transformer

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;Transformer模型自2017年由Vaswani等人在论文《Attention Is All You Need》中提出以来&#xff0c;已成为最具影响力的技术之一。这种模型设计的核心是自注意力机制&#xff0c;它允许模型在处理序列数据时&#xf…...

宠物健康新守护:智能听诊器引领科技突破

在宠物护理领域&#xff0c;一项令人瞩目的科技创新正逐渐兴起&#xff0c;那便是智能听诊器。这款革命性的设备以前所未有的准确性和便利性&#xff0c;为宠物主人提供了一种全新的健康监测体验。 只需将智能听诊器轻轻放置在爱宠的身上&#xff0c;它便立即开始工作&#xf…...

KITTI 3D 数据可视化

引言 KITTI 视觉基准测试套件&#xff08;KITTI Vision Benchmark Suite&#xff09;提供了大量用于理解自动驾驶场景的工具。尤其是3D数据可视化在分析和解释传感器&#xff08;如激光雷达&#xff09;与环境的复杂交互中起到了至关重要的作用。本文将详细探讨KITTI数据集中3…...

旅游数据可视化:免费工具让复杂数据变得简单易懂

随着旅游业的蓬勃发展&#xff0c;海量的数据如同繁星点点&#xff0c;记录着每一位旅者的足迹与偏好。然而&#xff0c;如何将这些复杂的数据转化为直观、易懂的信息&#xff0c;为旅游企业精准决策、为消费者提供更加个性化的服务&#xff0c;成为了行业内外共同关注的焦点。…...

数据结构进阶:使用链表实现栈和队列详解与示例(C, C#, C++)

文章目录 1、 栈与队列简介栈&#xff08;Stack&#xff09;队列&#xff08;Queue&#xff09; 2、使用链表实现栈C语言实现C#语言实现C语言实现 3、使用链表实现队列C语言实现C#语言实现C语言实现 4、链表实现栈和队列的性能分析时间复杂度空间复杂度性能特点与其他实现的比较…...

【线程系列之五】线程池介绍C语言

一、基本概念 1.1 概念 线程池&#xff08;Thread Pool&#xff09;是一种基于池化技术管理线程的机制&#xff0c;旨在减少线程创建和销毁的开销&#xff0c;提高系统资源的利用率&#xff0c;以及更好地控制系统中同时运行的线程数量。线程池通过预先创建一定数量的线程&am…...

【学习css3】使用flex和grid实现等高元素布局

过往的实现方法是使用浮动加计算布局来实现&#xff0c;当flex和grid问世时&#xff0c;这一切将变得简单起来 一、简单的两列实现 1、先看页面效果 2、css代码 .container {padding: 10px;width: 100ch;margin: 0 auto;box-shadow: inset 0 0 0 2px #ccc;}.column {margin: 2…...

如何防止Eclipse格式化程序在行注释开头插入空格

格式化前&#xff1a; //foo bar 格式化后&#xff1a; // foo bar 这种看着不是很舒服。如果不让格式化时自动在注释符后面插入空格呢&#xff1f; 要在Eclipse中进行代码格式化时防止在行注释&#xff08;‌//&#xff09;‌后面自动增加空格&#xff0c;‌可以通过调整…...

Nextjs 调用组件内的方法

在 Next.js 中&#xff0c;如果你想从一个组件外部调用组件内部的方法&#xff0c;可以使用 React 的 useRef 钩子来引用组件实例并调用其方法。这种方法主要适用于类组件&#xff0c;但也可以用于函数组件&#xff0c;通过将方法暴露在 ref 对象上。 以下是一个示例&#xff…...

ip地址是电脑还是网线决定的

在数字化时代的浪潮中&#xff0c;网络已经成为了我们日常生活和工作不可或缺的一部分。当我们谈论网络时&#xff0c;IP地址无疑是一个核心的概念。然而&#xff0c;关于IP地址的分配和决定因素&#xff0c;很多人可能存在误解。有些人认为IP地址是由电脑决定的&#xff0c;而…...

Hadoop中HDFS、Hive 和 HBase三者之间的关系

HDFS&#xff08;Hadoop Distributed File System&#xff09;、Hive 和 HBase 是 Hadoop 生态系统中三个重要的组件&#xff0c;它们各自解决了大数据存储和处理的不同层面的问题。我们用大白话来解释这三个组件之间的关系&#xff1a; HDFS - 数据的仓库&#xff1a; HDFS 是…...

opencv—常用函数学习_“干货“_10

目录 二七、离散余弦变换 执行离散余弦变换 (dct) 和逆变换 (idct) 解释 实际应用 JPEG压缩示例&#xff08;简化版&#xff09; 二八、图像几何变换 仿射变换 (warpAffine 和 getAffineTransform) 透视变换 (warpPerspective 和 getPerspectiveTransform) 旋转变换 (g…...

Jmeter二次开发Demo

Jmeter二次开发Demo 前言 在上一集&#xff0c;我们已经完成了JMX脚本的分析&#xff0c;大致了解了JMX脚本的基本元素。 那么在这一集&#xff0c;我们将会介绍一下Jmeter二次开发的Demo。 Demo代码 那么话不多说&#xff0c;我们就直接上代码。 public class TestStress…...

MongoDB综合实战篇(超容易)

一、题目引入 在MongoDB的gk集合里插入以下数据&#xff1a; 用语句完成如下功能&#xff1a; &#xff08;1&#xff09;查询张三同学的成绩信息 &#xff08;2&#xff09;查询李四同学的语文成绩 &#xff08;3&#xff09;查询没有选化学的同学 &#xff08;4&#xf…...

框架设计MVVM

重点&#xff1a; 1.viewmodel 包含model 2.view包含viewmodel,通过驱动viewmodel去控制model的数据和业务逻辑 // Test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> #include <vector>using namespace std;#p…...

RK3399基础部分

1.RK3399介绍 基础特性&#xff1a; 高达1.8GHz的双核Cortex-A72 四核Cortex-A53高达1.4GHz NPU高达3.0TOPS Mali-T860MP4 GPU 双通道DDR3/DDR3L/LPDDR3/LPDDR4 4K超高清H265/H264/VP9 HDR10/HLG H264编码器 双MIPI CSI和ISP USB Type-CGPU: 图形处理器&#xff08;英语&…...

linux高级编程(广播与组播)

广播与组播&#xff1a; 广播&#xff1a; 局域网&#xff0c;一个人发所有人都能收&#xff08;服务器找客户端&#xff09;&#xff0c;&#xff08;发给路由器的广播地址后后路由器自动给所有人发&#xff0c;可用于服务器找客户端&#xff09; 只能udp来做 setsocketopt…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...