【Linux】信号量,线程池

目录

信号量

初始化​编辑

销毁

 等待

发布

基于环形队列的生产消费模型

问题解答:

代码:

线程池

线程池的实现

(1)初始化,构造大致框架

(2)创建线程

(3)创建任务

(4)完善线程要执行的任务

(5)更新初始化Init()函数

代码:

日志


信号量

POSIX 信号量和 SystemV 信号量作用相同, 都是用于同步操作, 达到无冲突的访问共
享资源目的。 但 POSIX 可以用于线程间同步。

信号量本质就是一个计数器,对公共资源的预定机制;


初始化

sem_t _data_sem;
sem_init(&_data_sem,0,0);
//pshared:0 表示线程间共享, 非零表示进程间共享
//value: 信号量初始值

销毁

sem_destroy(&_data_sem);

 等待

功能: 等待信号量, 会将信号量的值减 1;

    void P(sem_t &s)//申请信号量,--{sem_wait(&s);}

发布

功能: 发布信号量, 表示资源使用完毕, 可以归还资源了。 将信号量值加 1。

    void V(sem_t &s)//释放资源,++{sem_post(&s);}

基于环形队列的生产消费模型

之前我们写的生产消费模型是基于 queue 的,其空间可以动态分配,现在基于固定大小
的环形队列重写这个程序(POSIX 信号量) ;

环形队列采用数组模拟, 用模运算来模拟环状特性;

(1)初始化

(2)完善生产消费代码

(3)完善main

当然任务不止是参数,也可以是类:

问题解答:

(1)上面的是单生产单消费的例子,那多生产多消费呢?

两个锁:多个生产者竞争一个锁,多个消费者竞争一个锁;其实本质还是单生产单消费;但是由于处理数据和构造数据都需要时间,所以多生产多消费效率更改高;

(2)在多生产多消费时,是先加锁还是先申请信号量?

先申请信号量;这个问题就好比你去电影院看电影,是先排队(此时你并没有买票)还是先买票的问题,肯定是先买票效率更高,要不然排到你,你没有电影票还是进不去;

(3)为什么信号量对资源进行使用、申请时,不判断一下条件是否满足?

因为信号量本身就是一个判断条件;

代码:
#pragma once#include<iostream>
#include<pthread.h>
#include<semaphore.h>
#include<vector>
#include<string>
#include<unistd.h>
#include<sys/types.h>using namespace std;
const int  defaultcp =5;
template<typename T>
class Ringqueue
{
private:void P(sem_t &s)//申请信号量,--{sem_wait(&s);}void V(sem_t &s)//释放资源,++{sem_post(&s);}
public:Ringqueue(int max_cp = defaultcp):_max_cp(max_cp),_ringqueue(max_cp),_c_step(0),_p_step(0){sem_init(&_data_sem,0,0);sem_init(&_space_sem,0,max_cp);}~Ringqueue(){sem_destroy(&_data_sem);sem_destroy(&_space_sem);}void Push(const T &in)//生产{P(_space_sem);_ringqueue[_p_step]=in;_p_step++;_p_step%=_max_cp;V(_data_sem);}void Pop(T *out)//消费{P(_data_sem);*out=_ringqueue[_c_step];_c_step++;_c_step%=_max_cp;V(_space_sem);}private:vector<T>_ringqueue;int _p_step;int _c_step;int _max_cp;sem_t _data_sem;sem_t _space_sem;
};

线程池

线程池其实就是一种线程的使用模式;

线程过多会带来调度开销, 进而影响缓存局部性和整体性能。 而线程池维护着多个线程, 等待着监督管理者分配可并发执行的任务。 这避免了在处理短时间任务时创建与销毁线程的代价。 线程池不仅能够保证内核的充分利用, 还能防止过分调度。

线程池的实现

(1)初始化,构造大致框架

大致框架要有多个线程(用vector维护),要有任务队列(task_queue)能生产任务;

(2)创建线程

完成线程的创建,这里我直接用的上一篇文章自己封装的线程;

(3)创建任务

(4)完善线程要执行的任务

(5)更新初始化Init()函数

这样就完成了线程池的主要内容了,剩下的就是修改一下细节部分即可;

线程池的实现:构成出大致框架,在任务的函数中,注意如果任务列表中没有任务,那么线程就要处于等待状态,如果创建出一个任务后,就可以唤醒一个线程去执行即可;

代码:
#pragma once#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <queue>
#include "Thread.hpp"using namespace std;
const int defaultnum = 5;
template <typename T>
class ThreadPool
{
private:void WakeUpAll(){pthread_cond_broadcast(&_cond);}void Lock(){pthread_mutex_lock(&_mutex);}void Unlock(){pthread_mutex_unlock(&_mutex);}void WakeUp(){pthread_cond_signal(&_cond);}bool isEmpty(){return _task_queue.empty();}void HandlerTask(const string &name){while (true){// 取任务Lock();while (isEmpty() && _isrunning){// 休眠_sleep_num++;pthread_cond_wait(&_cond, &_mutex);_sleep_num--;}if (isEmpty() && !_isrunning){cout << name << "quit..." << endl;Unlock();break;}// 有任务T t = _task_queue.front();_task_queue.pop();Unlock();// 处理任务t();cout << name << t.Excute() << "任务处理完" << endl;}}public:ThreadPool(int thread_num = defaultnum) : _thread_num(thread_num), _isrunning(false), _sleep_num(0){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}void Init(){func_t func = bind(&ThreadPool::HandlerTask, this, std::placeholders::_1);// 创建线程for (int i = 0; i < _thread_num; i++){string name = "thread-" + to_string(i + 1);_threads.emplace_back(name, func);}}void Start(){_isrunning = true;for (auto &thread : _threads){thread.start();}}void Stop(){Lock();_isrunning = false;WakeUpAll();Unlock();}void Equeue(const T &in){Lock();if (_isrunning){// 生产任务_task_queue.push(in);// 唤醒线程if (_sleep_num > 0){WakeUp();}}Unlock();}private:int _thread_num;vector<Thread> _threads; // 线程queue<T> _task_queue;    // 任务,共享资源bool _isrunning;int _sleep_num; // 休眠的个数pthread_mutex_t _mutex;pthread_cond_t _cond;
};

日志

日志:软件运行的记录信息、向显示器打印、向文件打印、特定的格式;

【日志等级】【pid】【filename】【filenumber】【time】日志内容(支持可变参数)

日志等级:DEBUG、INFO、WARNING、ERROR、FATAL(致命的);

在初始化的时候,主要就是可变参数的初始化

其实写到上面这一步就以及完成的日志的实现;

我们来运行一下代码来看看:

main函数:

    cout<<gettime()<<endl;Log lg;lg.logMessage("main.cc",10,DEBUG,"hello %d,world%c,hello %f\n",10,'A',3.14);

 

下面我们只需要完善一下使该日志信息可以向显示器中打印,也可以向文件中打印;

设置一个类型_type;默认是向显示器打印;在执行打印代码时,只需要判断一下_type即可;

如果是向显示器打印,直接printf即可;如果是文件中打印,需要先打开对应的文件,在将日志信息写入;

完整代码:

#pragma once#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <ctime>
#include <stdarg.h>
// #include<stdio.h>
#include<ostream>
#include <fstream>using namespace std;#define SCREEN_TYPE 1
#define FILE_TYPE 2
const string glogfile ="./log.txt";// 日志等级
enum
{DEBUG = 1,INFO,WARNING,ERROR,FATAL
};string levelTo_string(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";}
}string gettime()
{time_t now = time(nullptr); // now就是时间戳struct tm *curr_time = localtime(&now);char buff[128];snprintf(buff, sizeof(buff), "%d-%02d-%02d : %02d-%02d-%02d",curr_time->tm_year + 1900,curr_time->tm_mon + 1,curr_time->tm_mday,curr_time->tm_hour,curr_time->tm_min,curr_time->tm_sec);return buff;
}class Logmessage
{
public:string _level;pid_t _pid;string _filename;int _filenumber;string _curr_time;string _message_info;
};class Log
{
private:void FlushLogScreen(Logmessage &lg){printf("[%s][%d][%s][%d] %s",lg._level.c_str(),lg._pid,lg._filename.c_str(),lg._filenumber,lg._message_info.c_str());}void FlushLogFile(Logmessage &lg){ofstream out(_logfile.c_str());if(!out.is_open())return;char buff[2048];snprintf(buff,sizeof(buff),"[%s][%d][%s][%d] %s",lg._level.c_str(),lg._pid,lg._filename.c_str(),lg._filenumber,lg._message_info.c_str());out.write(buff,strlen(buff));out.close();}public:Log(const string &logfile = glogfile) : _type(SCREEN_TYPE), _logfile(logfile){}~Log(){}void Enable(int type){_type = type;}void FlushLog(Logmessage &lg){switch (_type){case SCREEN_TYPE:FlushLogScreen(lg);break;case FILE_TYPE:FlushLogFile(lg);break;}}void logMessage(string filename, int filenumber, int level, const char *format, ...){Logmessage lg;lg._level = levelTo_string(level);lg._pid = getpid();lg._filename = filename;lg._filenumber = filenumber;lg._curr_time = gettime();va_list ap;va_start(ap, format);char log_info[1024];vsnprintf(log_info, sizeof(log_info), format, ap);va_end(ap);lg._message_info = log_info;FlushLog(lg);}private:int _type;string _logfile;
};

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

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

相关文章

Unity 世界空间(World Space)UI被模型遮挡的解决办法(Overlay摄像机)

问题&#xff1a; 想要显示掉落的物品名&#xff0c;但是这个世界空间的UI层会被模型遮挡&#xff0c;如下&#xff1a; 解决&#xff1a; 1.新建一个专门的物品名图层&#xff0c;如ItemUI 2.在主摄像机下新建一个子摄像机ItemCamera&#xff0c;渲染类型设置为Overlay&#…

Unity加载界面制作

效果 UI部分 结构 说下思路: 因为是加载界面,所以最上层是一个Panel阻止所有的UI交互,这个Panel如果有图片就加一个图片,如果没有可以把透明度调到最大,颜色设为黑色. 下面最核心的就是一个进度条了,有图片的话,将进度条的底放进来,将进度条锚点设为下中,将滑动块的尺寸设为0.…

迈威通信西安采矿展大放异彩,驱动煤矿智能转型加速跑

金秋十月&#xff0c;一场矿业技术的盛宴如约而至。10月23日至25日&#xff0c;中国(西安)国际采矿技术交流及设备展览会在西安临空会展中心圆满落下帷幕。迈威通信&#xff0c;作为矿业通信与自动化解决方案的卓越提供商&#xff0c;此次以 “布局多元融合网络&#xff0c;赋能…

SwiftUI 中 List 或 Form 子视图关联的 swipeAction 导致展开动画异常的解决

问题现象 小伙伴们都知道,在 SwiftUI 中更快捷的增强 List 或 Form 子视图(Cell)交互功能的方法是使用 swipeAction 修改器。不过,对其使用稍有不慎也会横生枝节。 如上图所示,不适当的设置 Cell 视图布局会使 swipeAction 无法生成正确的收缩和展开动画。对此我们有什么…

微信小程序文字转语音播报案例

插件申请 在小程序官方申请同声传译插件&#xff0c;地址&#xff1a; mp.weixin.qq.com 引入插件 在app.json中加入 "plugins": {"WechatSI": {"version": "0.3.6","provider": "wx069ba97219f66d99"}},封装…

南京林业大学生态学博士在1区top期刊揭示人工林发育促进土壤团聚体的形成与稳定:对土壤碳氮固存的启示

本文首发于“生态学者”微信公众号&#xff01; 文章信息 第一作者&#xff1a;石珂 通讯作者&#xff1a;阮宏华教授 通讯单位&#xff1a;南京林业大学 原文链接&#xff1a;https://doi.org/10.1016/j.catena.2024.108363 亮点 •土壤团聚体的稳定性随着林分发育而增…

接口测试(五)jmeter——get请求

一、get请求——短信验证码&#xff08;示例仅供参考&#xff09; 1. get请求&#xff1a;传参数据直接拼接在地址后面&#xff0c;jmeter不需要设置请求头content-type 注&#xff1a;短信验证码接口&#xff0c;返回结果中不会返回短信验证码&#xff0c;是存在数据库表中&a…

【C++初阶】一文讲通C++内存管理

文章目录 1. C/C内存分布2. C语言中动态内存管理方式3. C内存管理方式3. 1 new/delete操作内置类型3. 2 new和delete操作自定义类型 4. new与delete的原理4. 1 operator new与operator delete函数4. 2 内置类型4. 3 自定义类型 5. 定位new表达式(placement-new)6. malloc/free和…

校园资讯平台|校园资讯平台系统|基于java和小程序的校园资讯平台设计与实现(源码+数据库+文档)

校园资讯平台 目录 基于java和小程序的校园资讯平台设计与实现 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff0c…

【mysql进阶】4-7. 通用表空间

通⽤表空间 - General Tablespace 1 通⽤表空间的作⽤和特性&#xff1f; ✅ 解答问题 通⽤表空间是使⽤ CREATE tablespace 语法创建的共享InnoDB表空间 通⽤表空间能够存储多个表的数据&#xff0c;与系统表空间类似也是共享表空间&#xff1b; 服务器运⾏时会把表空间元数…

【mysql进阶】4-6. InnoDB 磁盘文件

InnoDB 磁盘⽂件 1 InnoDB存储引擎包含哪些磁盘⽂件&#xff1f; &#x1f50d; 分析过程 ✅ 解答问题 InnoDB的磁盘⽂件主要是表空间⽂件和其他⽂件&#xff0c;表空间包括&#xff1a;系统表空间、独⽴表空间、通⽤表空间、临时表空间和撤销表空间&#xff1b;其他⽂件有重做…

springboot入门学习笔记

在我们创建了一个Springboot项目之后&#xff0c;我们会看到有很多文件夹和文件 Springboot程序中各类文件的意义 一.pom.xml 在 Spring Boot 项目中&#xff0c;pom.xml&#xff08;Project Object Model&#xff09;文件是 Maven 构建工具的核心配置文件。起到项目信息定义…

OpenCV中的图像通道合并

在计算机视觉和图像处理领域&#xff0c;OpenCV是一个强大的工具库&#xff0c;它提供了从基本操作到复杂算法的广泛功能。今天&#xff0c;我们将通过一个简单的示例来探索OpenCV中的图像通道处理&#xff0c;特别是如何操作和理解BGR与RGB颜色空间的差异。 Lena图像&#xf…

四,Linux基础环境搭建(CentOS7)- 安装Zookeeper

Linux基础环境搭建&#xff08;CentOS7&#xff09;-安装Zookeeper 大家注意以下的环境搭建版本号&#xff0c;如果版本不匹配有可能出现问题&#xff01; 一、Zookeeper下载及安装 ZooKeeper是一个开源的分布式协调服务&#xff0c;由雅虎创建&#xff0c;是Google Chubby的…

解决 IntelliJ IDEA 中 Tomcat 日志乱码问题的详细指南

目录 前言1. 分析问题原因2. 解决方案2.1 修改 IntelliJ IDEA 的 JVM 选项2.2 配置 Tomcat 实例的 VM 选项2.2.1 设置 Tomcat 的 VM 选项2.2.2 添加环境变量 3. 进一步优化3.1 修改 Tomcat 的 logging.properties3.2 修改操作系统默认编码3.2.1 Windows 系统3.2.2 Linux 和 mac…

2024mathorcup大数据竞赛B题【电商品类货量预测及品类分仓规划】思路详解

问题 1&#xff1a;建立货量预测模型&#xff0c;对该仓储网络 350 个品类未来 3 个月&#xff08;7-9月&#xff09;每个月的库存量及销量进行预测&#xff0c;其中库存量根据历史每月数据预测月均库存量即可&#xff0c;填写表 1 的预测结果并放在正文中&#xff0c;并将完整…

强化学习数学原理学习(一)

前言 总之开始学! 正文 先从一些concept开始吧,有一个脉络比较好 state 首先是就是状态和状态空间,显而易见,不多说了 action 同理,动作和动作空间 state transition 状态转换,不多说 policy 策略,不多说 reward 奖励,不多说 MDP(马尔科夫) 这里需要注意到就是这个是无…

Java-图书管理系统

我的个人主页 欢迎来到我的Java图书管理系统&#xff0c;接下来让我们一同探索如何书写图书管理系统吧&#xff01; 1管理端和用户端 2建立相关的三个包&#xff08;book、operation、user&#xff09; 3建立程序入口Main类 4程序运行 1.首先图书馆管理系统分为管理员端和…

通过Docker Compose构建自己的Java项目

通过Docker Compose构建自己的Java项目 前置条件 安装了Docker,未安装的请移步:CentOS7 / CentOS8 安装 Docker-ce安装了Docker-Compose,未安装的请移步:在CentOS7、CentOS8系统下安装Docker Compose1. 配置阿里云镜像仓库 为了提高Docker镜像的下载速度,我们可以配置阿…

代码随想录算法训练营第46期Day42

leetcode.518.零钱兑换 class Solution { public: //求装满背包有几种方法&#xff0c;公式都是&#xff1a;dp[j] dp[j - nums[i]]; // 如果求组合数就是外层for循环遍历物品&#xff0c;内层for遍历背包。 // 如果求排列数就是外层for遍历背包&#xff0c;内层for循环遍历物…