Linux POSIX信号量 线程池

Linux POSIX信号量 线程池

  • 一. 什么是POSIX信号量?
  • 二. POSIX信号量实现原理
  • 三. POSIX信号量接口函数
  • 四. 基于环形队列的生产消费模型
  • 五. 线程池

一. 什么是POSIX信号量?

POSIX信号量是一种用于同步和互斥操作的机制,属于POSIX(Portable Operating System Interface) 标准的一部分。这一标准定义了操作系统应该为应用程序提供的接口,而POSIX信号量是在多线程和多进程环境下实现同步的一种方式。

信号量本质上是一个计数器,用于描述临界资源的数量。在多线程或多进程的情况下,当多个执行单元(线程或进程)需要访问共享资源时,使用信号量可以有效地协调它们的行为,避免竞争条件和提高程序的可靠性。

二. POSIX信号量实现原理

POSIX信号量的实现原理基于一个计数器和一个等待队列。关键的操作包括P操作和V操作

P操作:申请信号量,如果信号量计数器大于零,表示资源可用,计数器减一;如果计数器为零,线程将被阻塞,并加入等待队列。
V操作:释放信号量计数器加一,并唤醒等待队列中的一个线程。

具体实现原理如下:

  1. 信号量结构包括计数器和等待队列。
  2. 当计数器为零时,表示资源不可用,线程申请信号量时将被阻塞,并放入等待队列。
  3. 当计数器大于零时,表示资源可用,线程申请信号量时计数器减一,线程获得资源。
  4. 当释放信号量时,计数器加一,如果等待队列不为空,唤醒等待队列中的一个线程。

三. POSIX信号量接口函数

  1. sem_t 是一个数据类型,用于表示信号量。作为同步机制的一部分,信号量用于协调共享资源的访问。用户通过提供的接口函数(如 sem_init、sem_wait、sem_post)来操作信号量,

  2. 初始化信号量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);

sem: 指向要初始化的信号量的指针。
pshared: 0表示信号量在线程间共享,非零表示在进程间共享。
value: 信号量的初始值。
返回值:成功时返回0,失败时返回-1。

  1. 等待信号量
#include <semaphore.h>
int sem_wait(sem_t *sem); // P()

sem: 指向要等待的信号量的指针。
功能:等待信号量,将信号量的值减1。如果信号量的值为0,线程将被阻塞
返回值:成功时返回0,失败时返回-1。

  1. 释放信号量
#include <semaphore.h>
int sem_post(sem_t *sem); // V()

sem: 指向要发布的信号量的指针。
功能:释放信号量,表示资源使用完毕,将信号量的值加1。通常用于释放信号
返回值:成功时返回0,失败时返回-1。

  1. 销毁信号量
#include <semaphore.h>
int sem_destroy(sem_t *sem);

sem: 要销毁的信号量的指针。
返回值:成功时返回0,失败时返回-1。

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

  1. 环形队列简介
    环形队列是一种基于数组或链表的数据结构,具有循环特性。其关键特点包括循环性、高效性和固定大小。常用于缓冲区、循环缓存和生产者-消费者模型等场景。由于采用模运算,插入和删除操作的时间复杂度为O(1),使得其在实时系统和有限资源的应用中得以广泛应用。
    在这里插入图片描述

在这里插入图片描述
放数据操作:

等待生产者信号量: 通过 P(prodSemaphore),生产者等待信号量,确保有足够的空间可供数据生产。
将数据放入缓冲区: 数据被放入环形缓冲区的当前生产者索引位置 (buffer_[prodIndex])。 生产者索引 prodIndex 被更新,并通过取模操作确保索引在缓冲区容量内循环。
发送消费者信号量: 通过 V(consSemaphore),生产者通知消费者有新的数据可供消费。

拿数据操作:

等待消费者信号量: 通过 P(consSemaphore),消费者等待信号量,确保有足够的数据可供消费。
从缓冲区取出数据: 数据被从环形缓冲区的当前消费者索引位置取出 (buffer_[consIndex])。 消费者索引 consIndex
被更新,并通过取模操作确保索引在缓冲区容量内循环。
发送生产者信号量: 通过 V(prodSemaphore),消费者通知生产者有空间可供数据生产。

五. 线程池

什么是线程池?
线程池是一种常见的多线程使用模式。它通过维护一组线程,等待监督管理者分配可并发执行的任务。这种设计避免了在处理短时间任务时创建与销毁线程的开销,提高了系统性能。线程池通过保证内核的充分利用,同时防止过度调度,对于某些应用场景尤其有效。

实例:创建一个简单的固定数量线程池

#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <unistd.h>
using namespace std;// 线程数据结构
struct threaddata
{pthread_t tid;  // 线程ID
};// 任务类
class Task
{
public:Task(int data) : data_(data){}// 重载运算符,用于执行任务void operator()(){run();}
private:// 任务执行函数void run(){cout << "数据:" << data_ << endl;}int data_;
};// 线程池模板类
template<class T>
class ThreadPool
{
public:// 构造函数,默认线程数为6ThreadPool(int n = 6) : td(6){pthread_mutex_init(&mutex_, nullptr);  // 初始化互斥锁pthread_cond_init(&cond_, nullptr);    // 初始化条件变量}// 析构函数~ThreadPool(){pthread_mutex_destroy(&mutex_);    // 销毁互斥锁pthread_cond_destroy(&cond_);      // 销毁条件变量}// 线程处理函数static void* handler(void* args){ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(args);while (1){tp->lock();  // 加锁,保护临界区while (tp->isQueueEmpty()){tp->wait();  // 当任务队列为空时,等待条件变量}T data = tp->queueFront();  // 获取任务队列的队首元素tp->queuePop();  // 弹出任务队列的队首元素tp->unlock();  // 解锁,释放临界区data();  // 执行任务}}// 启动线程池void start(){for (int i = 0; i < td.size(); i++){pthread_create(&(td[i].tid), nullptr, handler, static_cast<void*>(this));  // 创建线程}}// 将任务放入任务队列void push(T& data){lock();               // 加锁,确保线程安全task.push(data);      // 将任务加入队列wakeup();             // 唤醒等待的线程unlock();             // 解锁,释放锁,允许其他线程访问任务队列}// 判断任务队列是否为空bool isQueueEmpty(){return task.empty();}// 获取任务队列的队首元素T& queueFront(){return task.front();}// 弹出任务队列的队首元素void queuePop(){task.pop();}public:// 加锁操作void lock(){pthread_mutex_lock(&mutex_);}// 解锁操作void unlock(){pthread_mutex_unlock(&mutex_);}// 等待条件变量void wait(){pthread_cond_wait(&cond_, &mutex_);}// 唤醒等待条件变量的线程void wakeup(){pthread_cond_signal(&cond_);}private:vector<threaddata> td;  // 线程数据queue<T> task;          // 任务队列pthread_mutex_t mutex_; // 互斥锁pthread_cond_t cond_;   // 条件变量
};int main()
{srand(time(nullptr));ThreadPool<Task> thread(6);  // 创建线程池,设置线程数为6thread.start();  // 启动线程池while (1){Task d(rand() % 100);thread.push(d);  // 将任务放入线程池sleep(1);}return 0;
}

线程池模板类 ThreadPool: 创建了一个线程池类,模板参数为任务类型 T,默认线程数为6。 使用 pthread 库提供的互斥锁和条件变量来实现线程同步。 提供了启动线程池的 start 函数,创建指定数量的线程,并在这些线程中执行 handler
函数。 提供了将任务推送到任务队列的 push 函数,该函数会将任务加入队列,唤醒等待中的线程。

任务类 Task: 任务类用于封装线程池中执行的具体任务,其中包含一个整数类型的数据。 通过重载 () 运算符实现了任务的执行函数,输出任务的数据。

线程处理函数 handler: 作为线程的入口函数,不断从任务队列中取出任务并执行。 使用互斥锁保护任务队列,条件变量用于在任务队列为空时等待新任务。 通过调用线程池的成员函数来实现任务的执行、入队、出队等操作。

主函数 main: 在主函数中,创建了一个 ThreadPool 对象,设置线程数为6,并启动线程池。 进入无限循环,每次循环生成一个随机数,创建一个包含该随机数的 Task 对象,并通过线程池的 push 函数将任务推送到任务队列中。
程序不断创建新的任务,由线程池中的线程执行。

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

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

相关文章

项目管理工具软件Maven趣闻

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Maven这个单词来自于意第绪语&#xff08;Yiddish&#xff09;&#xff0c;这是一种与德语和希伯来语有密切关系的犹太民族语言。在这个语境中&#xff0c;Maven意为“知识的…

ChatGPT高效提问—prompt实践(智能辅导-心理咨询-职业规划)

ChatGPT高效提问—prompt实践&#xff08;智能辅导-心理咨询-职业规划&#xff09; ​ 智能辅导是指利用人工智能技术&#xff0c;为学习者提供个性化、高效的学习辅助服务。它基于大数据分析和机器学习算法&#xff0c;可以针对学习者的学习行为、状态和能力进行评估和预测&a…

MATLAB知识点:datasample函数(★★☆☆☆)随机抽样的函数,能对矩阵数据进行随机抽样

讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 节选自第3章&#xff1a;课后习题讲解中拓展的函数 在讲解第三…

数据类型与变量

目录 作业回顾 有关JDK, JRE, JVM三者&#xff1a; 判断题 新课学习 字面常量 数据类型 变量 整型变量 长整型变量 短整型变量 字节型变量 浮点型变量 字符型变量 布尔型变量 类型转换 自动类型转换&#xff08;隐式&#xff09; 强制类型转换&#xff08;显式…

Navicat安装使用连接MySQL

目录 安装登录MySQL登录MySQL用Navicat连接MySQL 安装 选择“我同意”&#xff0c;点击下一步。 选择安装的目标文件夹&#xff0c;点击下一步。 点击下一步。 点击下一步。 点击安装。 软件安装需要一些时间&#xff0c;请耐心等待 点击“完成”。 注册 输入 密钥&#x…

Crypto-RSA3

题目&#xff1a;&#xff08;BUUCTF在线评测 (buuoj.cn)&#xff09; 共模攻击 ​ 前提&#xff1a;有两组及以上的RSA加密过程&#xff0c;而且其中两次的m和n都是相同的&#xff0c;那么就可以在不计算出d而直接计算出m的值。 ​ 设模数为n&#xff0c;两个用户的公钥分别为…

LeetCode 0103.二叉树的锯齿形层序遍历:层序遍历 + 适时翻转

【LetMeFly】103.二叉树的锯齿形层序遍历&#xff1a;层序遍历 适时翻转 力扣题目链接&#xff1a;https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/ 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往…

Java与JavaScript同源不同性

Java是目前编程领域使用非常广泛的编程语言&#xff0c;相较于JavaScript&#xff0c;Java更被人们熟知。很多Java程序员想学门脚本语言&#xff0c;一看JavaScript和Java这么像&#xff0c;很有亲切感&#xff0c;那干脆就学它了&#xff0c;这也间接的帮助了JavaScript的发展…

HTML | DOM | 网页前端 | 常见HTML标签总结

文章目录 1.前端开发简单分类2.前端开发环境配置3.HTML的简单介绍4.常用的HTML标签介绍 1.前端开发简单分类 前端开发&#xff0c;这里是一个广义的概念&#xff0c;不单指网页开发&#xff0c;它的常见分类 网页开发&#xff1a;前端开发的主要领域&#xff0c;使用HTML、CS…

OpenCV中的边缘检测技术及实现

介绍: 边缘检测是计算机视觉中非常重要的技术之一。它用于有效地识别图像中的边缘和轮廓&#xff0c;对于图像分析和目标检测任务至关重要。OpenCV提供了多种边缘检测技术的实现&#xff0c;本博客将介绍其中的两种常用方法&#xff1a;Canny边缘检测和Sobel边缘检测。 理论介…

C语言程序设计(第四版)—习题7程序设计题

目录 1.选择法排序。 2.求一批整数中出现最多的数字。 3.判断上三角矩阵。 4.求矩阵各行元素之和。 5.求鞍点。 6.统计大写辅音字母。 7.字符串替换。 8.字符串转换成十进制整数。 1.选择法排序。 输入一个正整数n&#xff08;1&#xff1c;n≤10&#xff09;&#xf…

简易绘图软件(水一期)

哈哈&#xff01; 1、编写代码&#xff1a; 代码&#xff1a; main: #include <graphics.h> #include <music.h> #include <heker.h> #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )using…

25天物理探索旅程 - 第四天:光的奇妙旅程揭秘

第四天&#xff0c;我们的科普探险队将踏上一段非凡的旅程&#xff0c;目标是揭开光——这位宇宙间最具魔法特质的信使的秘密面纱。今天&#xff0c;我们将以一种轻松愉快、幽默风趣的方式探讨光的本质&#xff0c;像看一场生动有趣的魔术表演般&#xff0c;领略光那波粒二象性…

linux系统zabbix工具监控web页面

web页面监控 内建key介绍浏览器配置浏览器页面查看方式 监控指定的站点的资源下载速度&#xff0c;及页面响应时间&#xff0c;还有响应代码&#xff1b; web Scenario&#xff1a; web场景&#xff08;站点&#xff09;web page &#xff1a;web页面&#xff0c;一个场景有多…

WordPress站点如何实现发布文章即主动推送到百度快速收录和普通收录?

我们在WordPress后台成功发布文章之后&#xff0c;如果靠搜索引擎来抓取的话&#xff0c;可能会比较慢&#xff0c;所以十分有必要将我们成功发布的文章马上提交到百度、必应等搜索引擎中。下面boke112百科就跟大家说一说WordPress站点如何实现发布文章即主动推送到百度快速收录…

前端开发:Vue框架与前端部署

Vue Vue是一套前端框架&#xff0c;免除原生)avaScript中的DOM操作&#xff0c;简化书写。是基于MVVM(Model–View-ViewModel)思想&#xff0c;实现数据的双向绑定&#xff0c;将编程的关注点放在数据上。简单来说&#xff0c;就是数据变化的时候, 页面会自动刷新, 页面变化的时…

人工智能学习与实训笔记(七):神经网络之推荐系统处理

九、模型压缩与知识蒸馏 出于对响应速度&#xff0c;存储大小和能耗的考虑&#xff0c;往往需要对大模型进行压缩。 模型压缩方法主要可以分为以下四类&#xff1a; 参数修剪和量化&#xff08;Parameter pruning and quantization&#xff09;&#xff1a;用于消除对模型表…

云计算基础-存储基础

存储概念 什么是存储&#xff1a; 存储就是根据不同的应用程序环境&#xff0c;通过采取合理、安全、有效的方式将数据保存到某些介质上&#xff0c;并能保证有效的访问&#xff0c;存储的本质是记录信息的载体。 存储的特性&#xff1a; 数据临时或长期驻留的物理介质需要保…

【深度学习每日小知识】全景分割

全景分割 全景分割是一项计算机视觉任务&#xff0c;涉及将图像或视频分割成不同的对象及其各自的部分&#xff0c;并用相应的类别标记每个像素。与传统的语义分割相比&#xff0c;它是一种更全面的图像分割方法&#xff0c;传统的语义分割仅将图像划分为类别&#xff0c;而不…

【旧文更新】【优秀毕设】人脸识别打卡/签到/考勤管理系统(OpenCV+最简基本库开发、可移植树莓派 扩展网络图像推流控制 验证码及Excel邮件发送等功能)

【旧文更新】【优秀毕设】人脸识别打卡/签到/考勤管理系统&#xff08;OpenCV最简基本库开发、可移植树莓派 扩展网络图像推流控制 验证码及Excel邮件发送等功能&#xff09; 文章目录 关于旧文新发毕设结构主页面验证码识别效果管理页面人脸信息采集管理实时数据更新签到结果…