【Linux】多线程_7

文章目录

  • 九、多线程
    • 8. POSIX信号量
      • 根据信号量+环形队列的生产者消费者模型代码
      • 结果演示
  • 未完待续


九、多线程

8. POSIX信号量

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
创建多线程的信号量:
在这里插入图片描述
销毁多线程之间的信号量:
在这里插入图片描述
对信号量做P操作(申请资源):
在这里插入图片描述
对信号量做V操作(释放资源):
在这里插入图片描述

根据信号量+环形队列的生产者消费者模型代码

Makefile

cp_ring:Main.cc
	g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
	rm -f cp_ring

Thread.hpp

#ifndef __THREAD_HPP__
#define __THREAD_HPP__

#include <iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <pthread.h>

namespace ThreadModule
{
    template<typename T>
    using func_t = std::function<void(T&, const std::string& name)>;

    template<typename T>
    class Thread
    {
    public:
        void Excute()
        {
            _func(_data, _threadname);
        }
    public:
        Thread(func_t<T> func, T& data, const std::string &name="none-name")
            : _func(func)
            , _data(data)
            , _threadname(name)
            , _stop(true)
        {}

        static void *threadroutine(void *args)
        {
            Thread<T> *self = static_cast<Thread<T> *>(args);
            self->Excute();
            return nullptr;
        }

        bool Start()
        {
            int n = pthread_create(&_tid, nullptr, threadroutine, this);
            if(!n)
            {
                _stop = false;
                return true;
            }
            else
            {
                return false;
            }
        }

        void Detach()
        {
            if(!_stop)
            {
                pthread_detach(_tid);
            }
        }

        void Join()
        {
            if(!_stop)
            {
                pthread_join(_tid, nullptr);
            }
        }

        std::string name()
        {
            return _threadname;
        }

        void Stop()
        {
            _stop = true;
        }

        ~Thread() {}
    private:
        pthread_t _tid;
        std::string _threadname;
        T& _data;
        func_t<T> _func;
        bool _stop;
    };
}

#endif

RingQueue.hpp

#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <semaphore.h>

// 环形队列类模板
template<class T>
class RingQueue
{
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:
    RingQueue(int cap)
        :_cap(cap)
        ,_ring_queue(cap)
        ,_prodeucer_step(0)
        ,_consumer_step(0)
    {
        sem_init(&_room_sem, 0, _cap);
        sem_init(&_data_sem, 0, 0);
        pthread_mutex_init(&_prodeucter_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);
    }

    // 生产者的入队列函数
    void Enqueue(const T& in)
    {
        // 申请空间资源
        P(_room_sem);
        // 加锁
        Lock(_prodeucter_mutex);
        // 入队列
        _ring_queue[_prodeucer_step++] = in;
        // 环形,绕一圈
        _prodeucer_step %= _cap;
        // 解锁
        Unlock(_prodeucter_mutex);
        // 释放数据资源
        V(_data_sem);
    }

    // 消费者的出队列函数
    void Pop(T* out)
    {
        // 申请数据资源
        P(_data_sem);
        // 加锁
        Lock(_consumer_mutex);
        // 出队列
        *out = _ring_queue[_consumer_step++];
        _consumer_step %= _cap;
        // 解锁
        Unlock(_consumer_mutex);
        // 释放空间资源
        V(_room_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_room_sem);
        sem_destroy(&_data_sem);
        pthread_mutex_destroy(&_prodeucter_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }
private:
    // 数组模拟环形队列
    std::vector<T> _ring_queue;
    // 容量
    int _cap;
    // 生产者和消费者的位置指针
    int _prodeucer_step;
    int _consumer_step;
    // 信号量
    sem_t _room_sem;
    sem_t _data_sem;
    // 互斥锁
    pthread_mutex_t _prodeucter_mutex;
    pthread_mutex_t _consumer_mutex;
};

Task.hpp

#pragma once

#include <iostream>
#include <functional>

using Task = std::function<void()>;

void Download()
{
    std::cout << "Downloading..." << std::endl;
}

Main.cc

#include "RingQueue.hpp"
#include "Thread.hpp"
#include "Task.hpp"
#include <string>
#include <vector>
#include <unistd.h>

using namespace ThreadModule;
// 创建类型别名
using ringqueue_t = RingQueue<Task>;

// 消费者线程
void Consumer(ringqueue_t& rq, const std::string& name)
{
    while (true)
    {
        // 获取任务
        Task t;
        rq.Pop(&t);
        std::cout << "Consumer " << name << " : ";
        // 执行任务
        t();
    }
}

// 生产者线程
void Productor(ringqueue_t& rq, const std::string& name)
{
    while (true)
    {
        // 发布任务
        rq.Enqueue(Download);
        std::cout << "Productor " << name << " : " << "Download task" << std::endl;
        sleep(1);
    }
}

// 启动线程
void InitComm(std::vector<Thread<ringqueue_t>>* threads, int num, ringqueue_t& rq, func_t<ringqueue_t> func)
{
    for (int i = 0; i < num; i++)
    {
        // 创建一批线程
        std::string name = "thread-" + std::to_string(i + 1);
        threads->emplace_back(func, rq, name);
    }
}

// 创建消费者线程
void InitConsumer(std::vector<Thread<ringqueue_t>>* threads, int num, ringqueue_t& rq)
{
    InitComm(threads, num, rq, Consumer);
}

// 创建生产者线程
void InitProductor(std::vector<Thread<ringqueue_t>>* threads, int num, ringqueue_t& rq)
{
    InitComm(threads, num, rq, Productor);
}

// 等待所有线程结束
void WaitAllThread(std::vector<Thread<ringqueue_t>>& threads)
{
    for (auto& thread : threads)
    {
        thread.Join();
    }
}

// 启动所有线程
void StartAll(std::vector<Thread<ringqueue_t>>& threads)
{
    for (auto& thread : threads)
    {
        thread.Start();
    }
}

int main()
{
    // 创建阻塞队列,容量为5
    ringqueue_t* rq = new ringqueue_t(10);
    // 创建线程
    std::vector<Thread<ringqueue_t>> threads;
    // 创建 1个消费者线程
    InitConsumer(&threads, 1, *rq);
    // 创建 1个生产者线程
    InitProductor(&threads, 1, *rq);
    // 启动所有线程
    StartAll(threads);

    // 等待所有线程结束
    WaitAllThread(threads);

    return 0;
}

结果演示

在这里插入图片描述
这里演示的是单生产者单消费者的模型,可以在主函数改成多生产者多消费者的模型。


未完待续

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

38 IRF+链路聚合+ACL+NAT组网架构

38 IRF链路聚合ACLNAT组网架构 参考文献 34 IRF的实例-CSDN博客 35 解决单条链路故障问题-华三链路聚合-CSDN博客 36 最经典的ACL控制-CSDN博客 37 公私网转换技术-NAT基础-CSDN博客 32 华三vlan案例STP-CSDN博客 一 网络架构 二 采用的技术 1 vlan 2 ip 3 stp 4 链…

【问题记录】Docker配置mongodb副本集实现数据流实时获取

配置mongodb副本集实现数据流实时获取 前言操作步骤1. docker拉取mongodb镜像2. 连接mongo1镜像的mongosh3. 在mongosh中初始化副本集 注意点 前言 由于想用nodejs实现实时获取Mongodb数据流&#xff0c;但是报错显示需要有副本集的mongodb才能实现实时获取信息流&#xff0c;…

数据结构(Java):队列Queue集合力扣面试OJ题

1、队列 1.1 队列的概念 队列是一个特殊的线性表&#xff0c;只允许在一端&#xff08;队尾&#xff09;进行插入数据操作&#xff0c;在另一端&#xff08;对头&#xff09;进行删除数据。队列具有先进先出FIFO(First In First Out)的特性。 入队&#xff1a;数据只能从队尾…

【密码学】密码学数学基础:群的定义

一、群的定义 在密码学中&#xff0c;群&#xff08;Group&#xff09;的概念是从抽象代数借用来的&#xff0c;它是一种数学结构&#xff0c;通常用于描述具有特定性质的运算集合。 群的定义 群定义中的几个关键要素&#xff1a; 集合&#xff1a;首先&#xff0c;群是由一系…

ES快速开发,ElasticsearchRestTemplate基本使用以及ELK快速部署

最近博主有一些elasticsearch的工作&#xff0c;所以更新的慢了些&#xff0c;现在就教大家快速入门&#xff0c;并对一些基本的查询、更新需求做一下示例&#xff0c;废话不多说开始&#xff1a; 1. ES快速上手 es下载&#xff1a;[https://elasticsearch.cn/download/]()这…

以数据编织,重构数据管理新范式

大数据产业创新服务媒体 ——聚焦数据 改变商业 人工智能几乎统一了全球最顶尖科技公司的认知&#xff1a;这个时代&#xff0c;除了AI&#xff0c;没有第二条路可走。 人工智能的技术逻辑颇有一种“暴力美学”&#xff0c;它依托于海量大数据和超高算力的训练和推理&#xff…

PE73_E6_BLE

PE73_E6_BLE 产品参数 产品型号 PE73_E6_BLE 尺寸(mm) 180*130*13mm 显示技术 电子墨水屏 显示区域(mm) 163.2(H) * 97.92(V) 分辨率(像素) 800*480 像素尺寸(mm) 0.204*0.204 显示颜色 黑/白/红/黄/橙/蓝/绿 视觉角度 180 工作温度 0-50℃ …

使用自制Qt工具配合mitmproxy进行网络调试

在软件开发和网络调试过程中&#xff0c;抓包工具是不可或缺的。传统的抓包工具如Fiddler或Charles Proxy通常需要设置系统代理&#xff0c;这会抓到其他应用程序的网络连接&#xff0c;需要设置繁琐的过滤&#xff0c;导致不必要的干扰。为了解决这个问题&#xff0c;我们可以…

调用第三方API超时如何区分是连接超时还是响应超时

在Java中调用第三方接口时&#xff0c;遇到超时问题通常涉及两种类型的超时&#xff1a;连接超时(Connect Timeout)和响应超时(Read TimeOut) 要查看是对方响应超时还是自己方连接超时&#xff0c;可以通过设置Java的HttpClient的超时时间和捕获异常来判断。以下是一个示例&…

灌区流量监测设备:农田灌溉的“智慧眼”

随着现代农业的不断发展&#xff0c;对灌溉技术的要求也越来越高。传统的灌溉方式不仅效率低下&#xff0c;而且容易造成水资源的浪费。如今&#xff0c;灌区流量监测设备以其独特的优势&#xff0c;成为农田灌溉的新宠&#xff0c;被誉为农田的“智慧眼”。 精准把控&#xff…

Java 实验五:继承与接口

一、实验目的 1、通过实验内容&#xff0c;锻炼自身进行需求分析&#xff0c;系统设计以及编程开发的能力&#xff0c;了解软件开发的流程。 二、实验环境 Jdk 1.8&#xff1b; Eclipse 三、实验内容 试分析停车场系统的常用业务功能&#xff0c;梳理出基本需求&#xff0…

优阅达线上分享:快速上手 Tableau 计算功能

无论是想获取更深入的业务洞察&#xff0c;还是希望实现更复杂的数据图表&#xff0c;Tableau 计算都能助你实现需求。然而&#xff0c;对于没有数学或统计经验的用户来说&#xff0c;快速理解并掌握 Tableau 计算功能的逻辑和用法并非易事。 如果你刚接触 Tableau 计算不知从…

把ros消息转换成中文输出

把ros消息转换成中文输出 c实现 发布 //发布性能评估数据 /trilateration_time_log void publishTrilaterationLog(const int reflectorPanelPoints_size,const double duration_count,const std::string& resultType,const std::string& resultChineseMessage,cons…

python基础知识点(蓝桥杯python科目个人复习计划69)

做些基础题 第一题&#xff1a;微生物增值 题目描述&#xff1a; 假设有两种微生物x和y。 x出生后每隔3分钟分裂一次&#xff08;数目加倍&#xff09;&#xff0c;y出生后每隔2分钟分裂一次&#xff08;数目加倍&#xff09;。 一个新出生的x&#xff0c;半分钟之后吃掉一…

Git常用命令以及使用IDEA集成Gitee

目录 一、设置用户签名 二、初始化本地库 三、查看本地库状态 四、添加文件到暂存区 五、提交本地库 六、修改文件 七、版本穿梭 八、Git分支 九、分支的操作 9.1、查看分支 9.2、创建分支 9.3、切换分支 9.4、合并分支 十、团队协作 十一、Idea集成Git 11.1、配…

初识C++|类与对象(上)

&#x1f36c; mooridy-CSDN博客 &#x1f9c1;C专栏&#xff08;更新中&#xff01;&#xff09; 1. 类的定义 1.1 类定义格式 • class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省略。 类体中内容…

【Web服务与Web应用开发】【C#】VS2019 创建ASP.NET Web应用程序,以使用WCF服务

目录 0.简介 1.环境 2.知识点 3.详细过程 1&#xff09;创建空项目 2&#xff09;添加Web表单 3&#xff09;使用Web表单的GUI设计 4&#xff09;添加服务引用 5&#xff09;在Web的button函数中调用服务&#xff0c;获取PI值 6&#xff09;测试 0.简介 本文属于一个…

如何直接套用模板,快速搭建一个3D展示页面?

随着Web3D技术的飞速进步&#xff0c;网页设计实现了从平面二维到立体三维的华丽蜕变&#xff0c;这一变革为品牌营销领域注入了前所未有的互动活力。多样化的3D营销手段&#xff0c;不仅极大地吸引了消费者的目光&#xff0c;还显著提升了品牌形象与销售量&#xff0c;助力企业…

各类专业技术的pdf电子书

从业多年&#xff0c;收集了海量的pdf电子书籍&#xff0c;感兴趣的私聊。

探索智慧校园德育系统的学生考核之道

在当代教育领域&#xff0c;智慧校园德育管理系统的学生考核功能正逐渐成为推动学生全面发展的重要引擎。它不仅革新了传统德育评价的方式&#xff0c;还深度融入了学生日常的学习生活&#xff0c;成为连接学生、教师与学校管理层之间沟通与理解的桥梁。德育考核功能的核心在于…