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

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 函数将任务推送到任务队列中。
程序不断创建新的任务,由线程池中的线程执行。

相关文章:

Linux POSIX信号量 线程池

Linux POSIX信号量 线程池 一. 什么是POSIX信号量&#xff1f;二. POSIX信号量实现原理三. POSIX信号量接口函数四. 基于环形队列的生产消费模型五. 线程池 一. 什么是POSIX信号量&#xff1f; POSIX信号量是一种用于同步和互斥操作的机制&#xff0c;属于POSIX&#xff08;Po…...

Sentinel(理论版)

Sentinel 1.什么是Sentinel Sentinel 是一个开源的流量控制组件&#xff0c;它主要用于在分布式系统中实现稳定性与可靠性&#xff0c;如流量控制、熔断降级、系统负载保护等功能。简单来说&#xff0c;Sentinel 就像是一个交通警察&#xff0c;它可以根据系统的实时流量&…...

python3 获取某个文件夹所有的pdf文件表格提取表格并一起合并到excel文件

下面是一个完整的示例&#xff0c;其中包括了merge_tables_to_excel函数的定义&#xff0c;并且假设该函数的功能是从每个PDF文件中提取第一个表格并将其合并到一个Excel文件中&#xff1a; import os from pathlib import Path import pandas as pd import pdfplumber …...

【AIGC】Stable Diffusion的模型入门

下载好相关模型文件后&#xff0c;直接放入Stable Diffusion相关目录即可使用&#xff0c;Stable Diffusion 模型就是我们日常所说的大模型&#xff0c;下载后放入**\webui\models\Stable-diffusion**目录&#xff0c;界面上就会展示相应的模型选项&#xff0c;如下图所示。作者…...

【JavaEE】_HTTP请求首行详情

目录 1. URL 2. 方法 2.1 GET方法 2.2 POST方法 2.3 GET与POST的区别 2.4 低频使用方法 1. URL 在mysql JDBC中已经提到过URL的相关概念&#xff1a; 如需查看有关JDBC更多内容&#xff0c;原文链接如下&#xff1a; 【MySQL】_JDBC编程-CSDN博客 URL用于描述某个资源…...

Linux第48步_编译正点原子的出厂Linux内核源码

编译正点原子的出厂 Linux 内核源码&#xff0c;为后面移植linux做准备。研究对象如下&#xff1a; 1)、linux内核镜像文件“uImage” 路径为“arch/arm/boot”&#xff1b; 2)、设备树文件“stm32mp157d-atk.dtb” 路径为“arch/arm/boot/dts” 3)、默认配置文件“stm32m…...

程序员为什么不喜欢关电脑?

程序员为什么不喜欢关电脑&#xff1f; 本人40 最近待业。&#xff0c;希望 3月前能再就业吧&#xff01;就不喜欢关电脑 这个问题来说是不好习惯。毕竟你的电脑不是服务器&#xff0c;哈哈。但是程序员都很懒&#xff0c;能自动化的&#xff0c;就让机器干。我在此之前 也工作…...

【初始RabbitMQ】了解和安装RabbitMQ

RabbitMQ的概念 RabbitMQ是一个消息中间件&#xff1a;他可以接受并转发消息。例如你可以把它当做一个快递站点&#xff0c;当你要发送一个包 裹时&#xff0c;你把你的包裹放到快递站&#xff0c;快递员最终会把你的快递送到收件人那里&#xff0c;按照这种逻辑 RabbitMQ 是 …...

Linux第56步_根文件系统第3步_将busybox构建的根文件系统烧录到EMMC

1、第1次将“rootfs”打包 1)、打开第1个终端&#xff0c;准备在“mnt”目录下创建挂载目录“rootfs”&#xff1b; 输入“ls回车” 输入“cd /mnt回车” 输入“ls回车”&#xff0c;查看“mnt”目录下的文件和文件夹 输入“sudo mkdir rootfs回车”&#xff0c;在“mnt”…...

Linux进程间通信(三)-----System V消息队列

消息队列的概念及原理 消息队列实际上就是在系统当中创建了一个队列&#xff0c;队列当中的每个成员都是一个数据块&#xff0c;这些数据块都由类型和信息两部分构成&#xff0c;两个互相通信的进程通过某种方式看到同一个消息队列&#xff0c;这两个进程向对方发数据时&#x…...

Elasticsearch:混合搜索是 GenAI 应用的未来

在这个竞争激烈的人工智能时代&#xff0c;自动化和数据为王。 从庞大的存储库中有效地自动化搜索和检索信息的过程的能力变得至关重要。 随着技术的进步&#xff0c;信息检索方法也在不断进步&#xff0c;从而导致了各种搜索机制的发展。 随着生成式人工智能模型成为吸引力的中…...

态、势、感、知的偏序、全序与无序

在态势感知中&#xff0c;"态"、"势"、"感"和"知"可以被理解为描述不同层次的概念。而在偏序、全序和无序方面&#xff0c;它们可以有不同的关系&#xff0c;简单地说&#xff0c;偏序关系表示部分的可比较性&#xff0c;全序关系表示…...

【从Python基础到深度学习】 8. VIM两种状态

一、安装 sudo apt install vim 二、VIM两种模式 - 命令状态/编辑状态 1.1 进入/退出VIM 进入VIM vim 退出vim :q <enter> 2.2 根目录下添加配置文件 window下创建vimrc类型文件内容如下&#xff1a; set nu set cursorline set hlsearch set tabstop4 使用Wins…...

java微服务面试篇

目录 目录 SpringCloud Spring Cloud 的5大组件 服务注册 Eureka Nacos Eureka和Nacos的对比 负载均衡 负载均衡流程 Ribbon负载均衡策略 自定义负载均衡策略 熔断、降级 服务雪崩 服务降级 服务熔断 服务监控 为什么需要监控 服务监控的组件 skywalking 业务…...

OpenAI 生成视频模型 Sora 论文翻译

系列文章目录 前言 视频生成模型作为世界模拟器 本技术报告的重点是 (1) 将所有类型的视觉数据转换为统一表示&#xff0c;以便对生成模型进行大规模训练的方法&#xff0c;以及 (2) 对索拉的能力和局限性的定性评估。 该报告不包括模型和实现细节。 许多先前的工作使用各种方…...

2.13日学习打卡----初学RocketMQ(四)

2.13日学习打卡 目录&#xff1a; 2.13日学习打卡一.RocketMQ之Java ClassDefaultMQProducer类DefaultMQPushConsumer类Message类MessageExt类 二.RocketMQ 消费幂消费过程幂等消费速度慢的处理方式 三.RocketMQ 集群服务集群特点单master模式多master模式多master多Slave模式-…...

ZigBee学习——BDB

✨本博客参考了善学坊的教程&#xff0c;并总结了在实现过程中遇到的问题。 善学坊官网 文章目录 一、BDB简介二、BDB Commissioning Modes2.1 Network Steering2.2 Network Formation2.3 Finding and Binding&#xff08;F & B&#xff09;2.4 Touchlink 三、BDB Commissi…...

使用Docker快速部署MySQL

部署MySQL 使用Docker安装&#xff0c;仅仅需要一步即可&#xff0c;在命令行输入下面的命令 docker run -d \--name mysql \-p 3306:3306 \-e TZAsia/Shanghai \-e MYSQL_ROOT_PASSWORD123456 \mysql MySQL安装完毕&#xff01;通过任意客户端工具即可连接到MySQL. 当我们执…...

力扣热题100_滑动窗口_3_无重复字符的最长子串

文章目录 题目链接解题思路解题代码 题目链接 3. 无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示…...

RM电控工程讲义

HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) 是一个回调函数&#xff0c;通常在STM32的HAL库中用于处理CAN&#xff08;Controller Area Network&#xff09;接收FIFO 0中的消息。当CAN接口在FIFO 0中有待处理的消息时&#xff0c;这个函数会被调用。 HAL库C…...

论文阅读:《Deep Learning-Based Human Pose Estimation: A Survey》——Part 1:2D HPE

目录 人体姿态识别概述 论文框架 HPE分类 人体建模模型 二维单人姿态估计 回归方法 目前发展 优化 基于热图的方法 基于CNN的几个网络 利用身体结构信息提供构建HPE网络 视频序列中的人体姿态估计 2D多人姿态识别 方法 自上而下 自下而上 2D HPE 总结 数据集…...

C语言——oj刷题——杨氏矩阵

目录 1. 理解杨氏矩形的特点 2. 实现杨氏矩形查找算法 3. 编写示例代码 当我们谈到杨氏矩形时&#xff0c;我们指的是一种在二维数组中查找目标元素的高效算法。它是由杨氏&#xff08;Yan Shi&#xff09;教授提出的&#xff0c;因此得名为杨氏矩形。 杨氏矩形问题的场景是…...

C++ 50道面试题

1. static关键字 1.全局static变量 存储位置&#xff1a;静态存储区&#xff0c;在程序运行期间一直存在 初始化&#xff1a; 未手动初始化的变量自动初始化为0 作用域&#xff1a; 从定义之处开始&#xff0c;到文件结束&#xff0c;仅能在本文件中使用 2.局部static变量…...

寒假学习记录14:JS字符串

目录 查找字符串中的特定元素 String.indexOf() &#xff08;返回索引值&#xff09; 截取字符串的一部分 .substring() &#xff08;不影响原数组&#xff09;&#xff08;不允许负值&#xff09; 截取字符串的一部分 .slice() &#xff08;不影响原数…...

【数学建模】【2024年】【第40届】【MCM/ICM】【C题 网球运动中的“动量”】【解题思路】

一、题目 &#xff08;一&#xff09; 赛题原文 2024 MCM Problem C: Momentum in Tennis In the 2023 Wimbledon Gentlemen’s final, 20-year-old Spanish rising star Carlos Alcaraz defeated 36-year-old Novak Djokovic. The loss was Djokovic’s first at Wimbledon…...

无人驾驶LQR控制算法 c++ 实现

参考博客&#xff1a; &#xff08;1&#xff09;LQR的理解与运用 第一期——理解篇 &#xff08;2&#xff09;线性二次型调节器(LQR)原理详解 &#xff08;3&#xff09;LQR控制基本原理&#xff08;包括Riccati方程具体推导过程&#xff09; &#xff08;4&#xff09;【基础…...

Karnaugh map (卡诺图)

【Leetcode】 289. Game of Life According to Wikipedia’s article: “The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.” The board is made up of an m x n grid of cells, wh…...

C# CAD 框选pdf输出

在C#中进行AutoCAD二次开发时&#xff0c;实现框选&#xff08;窗口选择&#xff09;实体并输出这些实体到PDF文件通常涉及以下步骤&#xff1a; public ObjectIdCollection GetSelectedEntities() {using (var acTrans HostApplicationServices.WorkingDatabase.Transaction…...

【Linux】 Linux 小项目—— 进度条

进度条 基础知识1 \r && \n2 行缓冲区3 函数介绍 进度条实现版本 1代码实现运行效果 版本2 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下一篇文章见&#xff01;&#xff01;&#xff01; 基础知识 1 \r &&a…...

Sora和Pika,RunwayMl,Stable Video对比!网友:Sora真王者,其他都是弟

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…...