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

【Linux】多线程_7

文章目录

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


九、多线程

8. POSIX信号量

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

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

Makefile

cp_ring:Main.ccg++ -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()
{// 创建阻塞队列,容量为5ringqueue_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;
}

结果演示

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


未完待续

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Spring解决循环依赖:三级缓存
  • 17-3 向量数据库之野望3 - SingleStoreDB 实践教程
  • MongoDB教程(六):mongoDB复制副本集
  • ant design form动态增减表单项Form.List如何进行动态校验规则
  • AI安全系列——[第五空间 2022]AI(持续更新)
  • 使用 Apache Pulsar 构建弹性可扩展的事件驱动应用
  • 【学习笔记】无人机(UAV)在3GPP系统中的增强支持(十)-服务体验保证的用例
  • 用虚拟机,可以在x86的电脑上虚拟出arm的电脑吗
  • 【轻松拿捏】Java-final关键字(面试)
  • Jmeter-单用户单表查询千条以上数据,前端页面分页怎么做
  • 【Git 学习笔记】第四章 git rebase 变基操作与相关示例(上)
  • 利用OSMnx进行城市路网数据的速度与通行时间推算及分析
  • 【.NET全栈】ASP.NET开发web应用——ASP.NET中的样式、主题和母版页
  • 今天此文堪比出师表最后一句话
  • Redis的中BitMap的应用
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • extjs4学习之配置
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • Java小白进阶笔记(3)-初级面向对象
  • jdbc就是这么简单
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Python - 闭包Closure
  • springboot_database项目介绍
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 如何用vue打造一个移动端音乐播放器
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 我感觉这是史上最牛的防sql注入方法类
  • 学习Vue.js的五个小例子
  • # Redis 入门到精通(九)-- 主从复制(1)
  • $$$$GB2312-80区位编码表$$$$
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (007)XHTML文档之标题——h1~h6
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (6)设计一个TimeMap
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (ZT)薛涌:谈贫说富
  • (补充):java各种进制、原码、反码、补码和文本、图像、音频在计算机中的存储方式
  • (不用互三)AI绘画工具应该如何选择
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (利用IDEA+Maven)定制属于自己的jar包
  • (四)React组件、useState、组件样式
  • (转)Unity3DUnity3D在android下调试
  • *Django中的Ajax 纯js的书写样式1
  • .NET Core 成都线下面基会拉开序幕
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .net 生成二级域名
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • .考试倒计时43天!来提分啦!
  • :=
  • @configuration注解_2w字长文给你讲透了配置类为什么要添加 @Configuration注解
  • @reference注解_Dubbo配置参考手册之dubbo:reference