Linux初阶——线程(Part3):POSIX 信号量 CP 模型变体

news2024/11/24 11:49:55

一、什么是 POSIX 信号量

信号量本质就是一个统计资源数量的计数器。​​​​​​​

1、PV 操作

pv操作就是一种让信号量变化的操作。其中 P 操作可以让信号量减 1(如果信号量大于 0),V 操作可以让信号量加 1.

2、信号量类型——sem_t

3、相关函数

3.1. 初始化信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);

参数:

pshared: 0表示线程间共享,非零表示进程间共享

value:信号量初始值

3.2. 销毁信号量

int sem_destroy(sem_t *sem);

3.3. P 操作

int sem_wait(sem_t *sem);

3.4. V 操作

int sem_post(sem_t *sem);

二、环形生产者消费者模型

1、原理

对于这个模型有一个规则:

  1. 只能有一个消费者和一个生产者访问这个环形内存;不能多个消费者和多个生产者同时访问这个环形内存。
  2. 消费者不能超过生产者,也不能套生产者的圈。
  3. 生产者不能套消费者的圈。 

 2、代码

#pragma once

#include <vector>
#include <semaphore.h>
#include <pthread.h>

const int default_cap = 5;

template<class T>
class ring_queue
{
private:
    void P(sem_t& sem) { sem_wait(&sem); }
    void V(sem_t& sem) { sem_post(&sem); }
    void Lock(pthread_mutex_t& mutex) { pthread_mutex_lock(&mutex); }
    void UnLock(pthread_mutex_t& mutex) { pthread_mutex_unlock(&mutex); }
public:
    ring_queue(int capacity = default_cap) : _capacity(capacity), _arr(std::vector<T>(capacity))
    {
        sem_init(&_sem_consumer, 0, 0);
        sem_init(&_sem_producer, 0, _capacity);
        pthread_mutex_init(&_mutex_consumer, nullptr);
        pthread_mutex_init(&_mutex_producer, nullptr);
    }

    ~ring_queue()
    {
        sem_destroy(&_sem_consumer), sem_destroy(&_sem_producer);
        pthread_mutex_destroy(&_mutex_consumer), pthread_mutex_destroy(&_mutex_producer);
    }

    void push(const T& in)
    {
        P(_sem_producer); // pv 操作一步到位,不会被中断,因此可以保证结果正确
        Lock(_mutex_producer); // _index_producer 下标互斥

        _arr[_index_producer] = in;
        _index_producer = (_index_producer + 1) % _capacity;

        UnLock(_mutex_producer);
        V(_sem_consumer);
    }

    T pop()
    {
        P(_sem_consumer); // pv 操作一步到位,不会被中断,因此可以保证结果正确
        Lock(_mutex_consumer); // _index_consumer 下标互斥

        T out = _arr[_index_consumer];
        _index_consumer = (_index_consumer + 1) % _capacity;

        UnLock(_mutex_consumer);
        V(_sem_producer);
        return out;
    }
private:
    std::vector<T> _arr;
    int _capacity;
    int _index_consumer, _index_producer;
    sem_t _sem_consumer, _sem_producer;
    pthread_mutex_t _mutex_consumer, _mutex_producer;
};

三、线程池 

1、结构

​​​​​​​​​​​​​​

因为中间的共享内存是被写任务的线程和拿任务的线程共享,因此我们可以把线程池看作是多生产者和多消费者的 CP 模型。

四、线程安全单例模式

1、什么是单例模式

只能建立一个对象的设计模式。

2、单例模式类型

2.1. 懒汉模式

获取实例的时候才开辟空间并初始化。

2.2. 饿汉模式

获取实例前就已经开辟空间并初始化好了。

3、代码(懒汉版)

#ifndef __THREAD_POOL_HPP__
#define __THREAD_POOL_HPP__

#include <vector>
#include <queue>
#include <pthread.h>

const int default_cap = 5;

class thread_info
{
    pthread_t _tid;
    std::string name;
};

template<class task>
class thread_pool
{
private:
    void lock() { pthread_mutex_lock(&_mutex); }
    void unlock() { pthread_mutex_unlock(&_mutex); }
    ~thread_pool() { pthread_mutex_destroy(&_mutex); pthread_cond_destroy(&_cond); }
    thread_pool(int capacity = default_cap) : _capacity(capacity), _tasks(std::vector<task>(capacity))
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    thread_pool(const thread_pool<task>& pool) = delete;
    thread_pool<task>& operator=(const thread_pool<task>& pool) = delete;
public:
    static thread_pool<task>* get_instance()
    {
        if (pt == nullptr) // 第一次申请单例时才要考虑多线程互斥问题,因为后面的 _pt 都不为空了,因此不用判断 _pt 是否为空
        {
            pthread_mutex_lock(&mutex);
            if (pt != nullptr) return pt;
            pthread_mutex_unlock(&mutex);
            thread_pool<task>* ret = new thread_pool<task>;
        }
        return ret;
    }
    // pthread_create 要求的函数是 void* start_routine(void* args),而如果不加 static,则为 void* start_routine(thread_pool<task>* this, void* args)
    static void* start_routine(void* args) 
    {
        thread_pool<task>* obj = static_cast<thread_pool<task>*>(args);

        obj->lock();
        while ((obj->_tasks).empty()) pthread_cond_wait(&_cond, &_mutex);
        task t = obj->pop();
        obj->unlock();

        // run t

        return t;
    }

    void start()
    {
        for (int i = 0; i < _capacity; i++)
            _threads[i].name = "thread - " + std::to_string(i),
            pthread_create(&(_threads[i]._tid), nullptr, start_routine, this);
    }

    void push(const task& in)
    {
        lock();
        _tasks.push(in);
        pthread_cond_signal(&_cond);
        unlock();
    }

    task pop() // 可保证在调 pop 方法时只有一个线程在调
    {
        task out = _tasks.front();
        _tasks.pop();
        return out;
    }
private:
    std::vector<thread_info> _threads;
    std::queue<task> _tasks;
    int _capacity;
    pthread_mutex_t _mutex; // 抢任务执行
    pthread_cond_t _cond; // 消费者的阻塞队列

    static thread_pool<task>* pt;
    static pthread_mutex_t mutex;
};

template<class task>
thread_pool<task>* thread_pool<task>::pt = nullptr;

template<class task>
pthread_mutex_t thread_pool<task>::mutex = PTHREAD_MUTEX_INITIALIZER;

#endif

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

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

相关文章

【C语言】预处理(预编译)详解(下)(C语言最终篇)

文章目录 一、#和##1.#运算符2.##运算符 二、预处理指令#undef三、条件编译1.单分支条件编译2.多分支条件编译3.判断符号是否被定义4.判断符号是否没有被定义 四、头文件的包含1.库头文件的包含2.本地头文件的包含3.嵌套包含头文件的解决方法使用条件编译指令使用预处理指令#pr…

ComfyUI和Photoshop相结合,PS内实现:文生图,图生图,高清放大,局部重绘,面部修复,设计师福音

本文主要介绍&#xff1a;ComfyUI和Photoshop相结合&#xff0c;一个平台实现&#xff1a;图像生成&#xff0c;放大&#xff0c;局部重绘&#xff0c;面部修复&#xff0c;实时绘画 简直是设计师的福音。 主要包括&#xff1a; Photoshop 的安装以及插件的安装 Creative Cl…

音视频入门基础:AAC专题(11)——AudioSpecificConfig简介

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…

Git (推送到远端仓库)

目录 一、在 gitee 上创建一个仓库 二、将项目推送到远程仓库 三、解释推送命令 一、在 gitee 上创建一个仓库 操作如下&#xff1a; 二、将项目推送到远程仓库 这里例举新的项目推送到远程仓库的例子&#xff1a; 打开仓库查看&#xff1a; 三、解释推送命令 添加远程仓库…

qt QAction详解

1、概述 QAction是Qt框架中的一个抽象类&#xff0c;用于表示用户界面中的一个动作&#xff08;action&#xff09;。这些动作可以绑定到菜单项、工具栏按钮或快捷键上&#xff0c;提供了一种灵活的方式来处理用户交互。QAction不仅包含了动作的名称、图标、提示信息等属性&am…

【FNENet】基于帧级非语言特征增强的情感分析

这篇文章语言极其晦涩难懂&#xff0c;内容和同专栏下的CENet中每一张图都百分之95相似&#xff0c;有些描述位置和内容都一模一样&#xff0c;还并且没有引用人家 abstract&#xff1a; 多模态情感分析&#xff08;Multimodal Sentiment Analysis&#xff0c; MSA&#xff09…

6. STM32之TIM实验--编码器接口()--(实验5:PWM驱动直流电机)

这篇文章是通用定时器的最后一章节&#xff0c;也就是编码器接口&#xff0c;主要是用来进行对精确测量旋转角度或速度的负载进行精确控制。 STM32 编码器模式详解-CSDN博客 STM32——编码器测速原理及STM32编码器模式_龙邱512编码器stm32历程-CSDN博客

Ambari里面添加hive组件

1.创建hive数据库 在添加hive组件之前需要做的事情&#xff0c;先在master这个虚拟机里面创建好hive 先进入虚拟机里面进入mysql 然后输入这个命令看看有没有自己创建的hive数据库 show databases;有的话会显示下面这个样子 没有的同学使用以下命令可以在MySQL中创建hive数…

stm32引脚PB3、PB4、PA15作为普通IO口用时,需要先解除调试端口复用

当项目调试的时候&#xff0c;发现PA15引脚无论配置输出高还是低或者输入&#xff0c;均只能输出3.3V的高电平。 目前STM的硬件调试有两种方法&#xff0c;JTAG和SW的方式&#xff0c;目前个人认为最好的方式就是SW&#xff0c;因为它只占用PA13和PA14两个IO。而JTAG还要多占用…

江协科技STM32学习- P33 实验-软件I2C读写MPU6050

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

快速遍历包含合并单元格的Word表格

Word中的合并表格如下&#xff0c;现在需要根据子类&#xff08;例如&#xff1a;果汁&#xff09;查找对应的品类&#xff0c;如果这是Excel表格&#xff0c;那么即使包含合并单元格&#xff0c;也很容易处理&#xff0c;但是使用Word VBA进行查找&#xff0c;就需要一些技巧。…

window免密登录虚拟机

环境 windows11 VirtualBox 图形用户界面 版本 7.1.2 r164945 (Qt6.5.3) CentOS-7-x86_64-Minimal-2009 虚拟机登录用户&#xff1a;root 1. 在虚拟机执行 1.1 生成秘钥&#xff08;后续直接回车就行&#xff09; ssh-keygen -t rsa -P 1.2 配置秘钥 cat ~/.ssh/id_rsa.pu…

标签之文字排版,图片,链接,音视频(HTML) 基础版

目录 标签之文字排版,图片,链接,音视频知识点: 练习题一: 效果: 练习题二: 效果: 标签之文字排版,图片,链接,音视频知识点: 超文本:链接 标记:标签<> 双标签 单标签 <br>//换行 <hr>//水平线 向后tab 向前shifttab html注释<!----> css /**/ …

UE5相机系统初探(一)

UE5相机系统初探&#xff08;一&#xff09; 和Unity类似&#xff0c;UE的相机也是由名为Camera的component控制的。那么&#xff0c;在UE中要如何实现一个跟随玩家的第三人称相机呢&#xff1f;假设我们已经有了一个表示玩家的类ACF_Character&#xff0c;首先第一步就是要先在…

短剧开发新模式:从内容创新到市场突围的全攻略

在探索短剧开发模式的过程中&#xff0c;理解其核心要素是至关重要的第一步。短剧作为一种独特的叙事形式&#xff0c;其特点是在极短的时间框架内讲述一个完整且吸引人的故事&#xff0c;这要求创作者必须具备高超的叙事技巧和对观众心理的深刻理解。创作者面临的首要挑战是如…

模型剪枝,如何把模型的使用成本降下来?

模型剪枝如何为企业节省百万预算&#xff1f; ©作者|DWT 来源|神州问学 近年来&#xff0c;大型语言模型&#xff08;LLM&#xff09;如GPT-3、LLaMA等在自然语言处理领域取得了令人瞩目的成果。然而&#xff0c;这些模型通常拥有数十亿甚至上千亿的参数&#xff0c;训练…

云效+mqtt实现本地构建和远程自动发版

之前写过一篇jenkinsmqtt实现本地构建和远程自动发版_jenkins远程调用和本地调用-CSDN博客 由于本地搭建jenkins实在太费机器了&#xff0c;这次改用云效搭建。不过云效并没有直接发送mqtt的方法&#xff0c;需要编写中转接口。 中转接口采用go-gin框架实现&#xff0c;代码如…

【蔬菜识别】Python+深度学习+CNN卷积神经网络算法+TensorFlow+人工智能+模型训练

一、介绍 蔬菜识别系统&#xff0c;本系统使用Python作为主要编程语言&#xff0c;通过收集了8种常见的蔬菜图像数据集&#xff08;‘土豆’, ‘大白菜’, ‘大葱’, ‘莲藕’, ‘菠菜’, ‘西红柿’, ‘韭菜’, ‘黄瓜’&#xff09;&#xff0c;然后基于TensorFlow搭建卷积神…

安装Blender并使用

前言 该系列记录了如何用Blenderpro来构建自己的场景数据集&#xff0c;从环境搭建到后期构建数据集的整个流程 本文章是第一部分&#xff0c;BlenderPrc2的安装以及环境配置 部分参考https://blog.csdn.net/weixin_49521551/article/details/121573334 官方文档https://dlr…

ApsaraMQ Serverless 能力再升级,事件驱动架构赋能 AI 应用

本文整理于 2024 年云栖大会阿里云智能集团高级技术专家金吉祥&#xff08;牟羽&#xff09;带来的主题演讲《ApsaraMQ Serverless 能力再升级&#xff0c;事件驱动架构赋能 AI 应用》 云消息队列 ApsaraMQ 全系列产品 Serverless 化&#xff0c;支持按量付费、自适应弹性、跨可…