当前位置: 首页 > 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…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...