【Linux】:线程(三)同步和消费者模型

线程的同步

  • 一.条件变量
  • 二.生产者和消费者模型
    • 1.概念和特点
    • 2.实现基于阻塞队列的生产者消费者模型

同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步。
竞态条件:因为时序问题,而导致程序异常,我们称之为竞态条件。

一.条件变量

当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。

例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量。

创建条件变量

在这里插入图片描述

cond:要初始化的条件变量。
attr:NULL。

等待条件满足

在这里插入图片描述

唤醒等待

在这里插入图片描述

一个示例

我想让每一个线程依次对一个全局变量cnt做++操作。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include <iostream>
using namespace std;
pthread_mutex_t mutex=PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;//初始化锁
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;//初始化条件变量

int cnt=0;

void *route(void *arg)
{
  char *id =(char*)arg;
  while(1) 
  {
    pthread_mutex_lock(&mutex);//上锁
    pthread_cond_wait(&cond,&mutex);//为什么在这等待?因为它在让线程等待时会自动释放锁

    cout<<id<<",cnt:"<<cnt++<<endl;

    pthread_mutex_unlock(&mutex);//解锁
  }
} 
int main()
{
  pthread_t t1, t2, t3, t4;
  pthread_create(&t1, NULL, route, (void*)"thread 1");
  pthread_create(&t2, NULL, route, (void*)"thread 2");
  pthread_create(&t3, NULL, route, (void*)"thread 3");
  pthread_create(&t4, NULL, route, (void*)"thread 4");
  sleep(1);
  cout<<"main thread begin:"<<endl;

  while(1)
  {
    sleep(1);
    pthread_cond_signal(&cond);//唤醒正在等待的一个线程,默认是第一个
    //pthread_cond_broadcast(&cond);//唤醒所有线程
    cout<<"signal one pthread...."<<endl;
  }

  pthread_join(t1, NULL);
  pthread_join(t2, NULL);
  pthread_join(t3, NULL);
  pthread_join(t4, NULL);

  pthread_mutex_destroy(&mutex);//销毁

  return 0;
}

在这里插入图片描述

可以看到到此,所创建的线程均以一定顺序对cnt进行了++操作。注意这里的顺序不一定是1234,也有可能是2341…但它一定呈现周期性。

二.生产者和消费者模型

1.概念和特点

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。

在这里插入图片描述

模型特点:

3种关系:消费者和消费者,生产者和生产者,生产者和消费者。

2种角色:消费者和生产者。

1个交易场所:特定的内存空间。

在这里插入图片描述

2.实现基于阻塞队列的生产者消费者模型

在多线程编程中阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)。

在这里插入图片描述

实现一个cp模型

设置水平线,当产品数量低于水平线时开始生产,当产品数量高于水平线时开始消费。

BlockQueue.hpp

#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>

template<class T>
class Blockqueue
{
public:
  Blockqueue(int capacity=20)
    :capacity_(capacity)//默认容量是20
  {
    pthread_mutex_init(&mutex_, nullptr);//初始化锁
    pthread_cond_init(&c_cond_, nullptr);//初始化消费者条件变量
    pthread_cond_init(&p_cond_, nullptr);//初始化生产者条件变量
    water_=capacity_/3;//水平线
  }

  T pop()
  {
    pthread_mutex_lock(&mutex_);//上锁
    if(q_.size()==0)
    {
      //如果没有产品,消费者开始等待
      pthread_cond_wait(&c_cond_,&mutex_);
    }
    T out=q_.front();
    q_.pop();
    if(q_.size()<water_)
    {
      //如果数量小于水平线,唤醒生产者
      pthread_cond_signal(&p_cond_);
    }

    pthread_mutex_unlock(&mutex_);//解锁
    return out;
  }

  void push(const T&in)
  {
    pthread_mutex_lock(&mutex_);//上锁
    if(q_.size()>capacity_)
    { 
      //如果数量高于容量,生产者开始等待
      pthread_cond_wait(&p_cond_,&mutex_); 
    }
    q_.push(in);
    if(q_.size()>water_)
    {
      //如果数量高于水平线,唤醒消费者
      pthread_cond_signal(&c_cond_);
    }

    pthread_mutex_unlock(&mutex_);//解锁
  }

  ~Blockqueue()
  {
    pthread_mutex_destroy(&mutex_);
    pthread_cond_destroy(&c_cond_);
    pthread_cond_destroy(&p_cond_);
  }

private:
  std::queue<T> q_; // 共享资源
  int capacity_;     //容量
  pthread_mutex_t mutex_;
  pthread_cond_t c_cond_;
  pthread_cond_t p_cond_;

  int water_;
};

main.cc

#include"Blockqueue.hpp"

void*Constumer(void*args)//消费者
{
  Blockqueue<int> *bq=static_cast<Blockqueue<int>*>(args);//强转

  while(1)
  {
    int out=bq->pop();
    std::cout<<"消费了一个数据:"<<out<<std::endl;
  }
}

void*Producer(void*args)//生产者
{
  Blockqueue<int> *bq=static_cast<Blockqueue<int>*>(args);
  int data=0;
  while(1)
  {
    sleep(1);
    bq->push(data);
    std::cout<<"生产了一个数据:"<<data++<<std::endl;
  }
}

int main()
{
  Blockqueue<int> *dp=new Blockqueue<int>();
  pthread_t t,c;
  pthread_create(&t,nullptr,Constumer,(void*)dp);
  pthread_create(&c,nullptr,Producer,(void*)dp);

  pthread_join(c,nullptr);
  pthread_join(t,nullptr);
  delete dp;
  return 0;
}


在这里插入图片描述

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

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

相关文章

【map】【动态规划】LeetCode2713:矩阵中严格递增的单元格数

本文涉及的基础知识点 二分查找算法合集 题目 给你一个下标从 1 开始、大小为 m x n 的整数矩阵 mat&#xff0c;你可以选择任一单元格作为 起始单元格 。 从起始单元格出发&#xff0c;你可以移动到 同一行或同一列 中的任何其他单元格&#xff0c;但前提是目标单元格的值 …

群晖(Synology)更换硬盘时间和精神双重折磨的教训

话说玩磁盘阵列的最后结果就是时间上负担不起&#xff0c;并且还被嫌弃。 在磁盘都到位后下一步就是要选择冗余类型了&#xff0c;对大部分人来说使用群晖自己提供的就好了&#xff0c;通常是 SHR。 什么是 SHR Synology Hybrid RAID&#xff08;SHR&#xff09;是 Synology…

为什么要使用国际语音群呼系统?

1.降本增效 通过批量导入客户的电话号码&#xff0c;由系统自动完成批量呼叫&#xff0c;企业可以节省人工拨号的费用&#xff0c;高效助力企业业务增长&#xff1b; 2.降低流失 通过批量群呼&#xff0c;企业可以724小时高并发无故障运行&#xff0c;智能锁定意向客户&…

【c语言】【visual studio】动态内存管理,malloc,calloc,realloc详解。

引言&#xff1a;随着大一期末的到来&#xff0c;想必许多学生都学到内存的动态管理这一部分了&#xff0c;看望这篇博客后&#xff0c;希望能解除你心中对这一章节的疑惑。 (・∀・(・∀・(・∀・*) 1.malloc详解 malloc的头文件是#include <sdtlib.h>,malloc - C Ref…

bugku--文件包含

点击 访问一下index.php 页面报错 既然是文件包含就可以想到php伪协议 这里我们需要访问本地文件系统 构造我们的payload ?filephp://filter/readconvert.base64-encode/resourceindex.php base64解码 得到我们的flag 提交就好啦 ?filephp://filter/readconvert.base64-e…

bugku--source

dirsearch扫一下 题目提示源代码&#xff08;source&#xff09; 也就是源代码泄露&#xff0c;然后发现有.git 猜到是git泄露 拼接后发现有文件 但是点开啥也没有 kali里面下载下来 wegt -r 下载网站的所有内容 ls 查看目录 cd 进入到目录里面 gie reflog 引用日志使用…

过滤(删除)迭代对象中满足指定条件的元素itertools.filterfalse()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 过滤(删除)迭代对象中 满足指定条件的元素 itertools.filterfalse() [太阳]选择题 请问以下代码输出的结果是&#xff1f; a [1, 2, 3, 4, 5] print("【显示】a ",a) import ite…

【SpringBoot】FreeMarker视图渲染

目录 一、FreeMarker 简介 1.1 什么是FreeMarker&#xff1f; 1.2 Freemarker模板组成部分 1.3 为什么要使用FreeMarker 二、Springboot集成FreeMarker 2.1 配置 2.2 数据类型 2.2.1 字符串 2.2.2 数值 2.2.3 布尔值 2.2.4 日期 2.3 常见指令 2.3.2 assign 2.3…

C++ 重载括号运算符示例

重载括号运算符的写法是&#xff0c; 返回值 operator() ( 表达式表 ) 参数个数不限&#xff1b; VC6新建一个单文档工程&#xff1b; 添加一个示例类&#xff0c;比较短&#xff0c;直接加到视类h文件的头部&#xff1b; class A { public:// 重载 括号 () 运算符int oper…

scratch魔法变变变 2023年12月中国电子学会图形化编程 少儿编程 scratch编程等级考试一级真题和答案解析

目录 scratch魔法变变变 一、题目要求 1、准备工作 2、功能实现 二、案例分析

webpack详细教程

1&#xff0c;什么是webpackwebpack | webpack中文文档 | webpack中文网 Webpack 不仅是一个模块打包器(bundler)&#xff0c;更完整的讲是一个前端自动化构建工具。在 Webpack 看来前端的所有资源文件(s/json/css/img/less/...)都会作为横块处理它将根据模块的依赖关系进行静…

进程概念【linux】

进程基础 在学习进程之前&#xff0c;首先要有一定的计算机硬件和软件基础。 硬件基础&#xff1a;冯诺依曼体系结构 如图&#xff0c;是计算机在硬件上的体系结构。 下面举出一些常见的输入输出设备&#xff08;有些设备只作输出设备&#xff0c;或者只作输入设备&#xff…

xtu oj 1328 数码和

题目描述 一个10进制数n在2∼16进制下可以得到的不同的数码和&#xff0c;求在这些数码和中出现次数最多的数码和。 比如20&#xff0c; 其中数码和2和4分别出现了3次&#xff0c;为最多出现次数。 输入 第一行是一个整数T(1≤T≤1000)&#xff0c;表示样例的个数。 以后每行…

【数据结构(十一·多路查找树)】B树、B+树、B*树(6)

文章目录 1. 二叉树 与 B树1.1. 二叉树存在的问题1.2. 多叉树 的概念1.3. B树 的基本介绍 2. 多叉树——2-3树2.1. 基本概念2.2. 实例应用2.3. 其他说明 3. B 树、B树 和 B*树3.1. B树 的介绍3.2. B树 的介绍3.2. B*树 的介绍 1. 二叉树 与 B树 1.1. 二叉树存在的问题 二叉树…

计算机视觉(P2)-计算机视觉任务和应用

一、说明 在本文中&#xff0c;我们将探讨主要的计算机视觉任务以及每个任务最流行的应用程序。 二、图像内容分类 2.1. 图像分类 图像分类是计算机视觉领域的主要任务之一[1]。在该任务中&#xff0c;经过训练的模型根据预定义的类集为图像分配特定的类。下图是著名的CIFAR…

大数据技术之Hive(超级详细)

第1章 Hive入门 1.1 什么是Hive Hive&#xff1a;由Facebook开源用于解决海量结构化日志的数据统计。 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张表&#xff0c;并提供类SQL查询功能。 本质是&#xff1a;将HQL转化成MapReduce程序 …

TensorFlow学习笔记--(4)神经网络模型-数据集预处理

神经网络初步 以scikit-leran鸢尾花为例 通过scikit-learn库自带的鸢尾花数据集 来测试数据的读入 from sklearn import datasets from pandas import DataFrame import pandas as pdx_data datasets.load_iris().data # .data返回iris数据集所有输入特征 y_data dataset…

【51单片机系列】proteus中创建16x16LED点阵

本文参考来源&#xff1a; Proteus8.6中16x16LED点阵制作教程【Proteus】16乘16点阵滚动播放 文章目录 一、测试proteus中的8x8点阵驱动方式1.1 测试电流通过方向1.2 测试行列控制接口 二、使用proteus中的8x8点阵制作16x16LED点阵三、测试制作的16x16LED点阵四、使用自制的16x…

06 python 文件基础操作

6.1 .1文件读取操作 演示对文件的读取 # 打开文件 import timef open(02_word.txt, r, encoding"UTF-8") print(type(f))# #读取文件 - read() # print(f读取10个字节的结果{f.read(10)}) # print(f读取全部字节的结果{f.read()})# #读取文件 - readLines() # lines…

Python——数据库操作

目录 &#xff08;1&#xff09;安装Flask-SQLAlchemy &#xff08;2&#xff09;使用Flask-SQLAlchemy操作数据库 &#xff08;3&#xff09;连接数据库 •创建数据表 •增加数据 •查询数据 •更新数据 •删除数据 Flask-SQLAlchemy是Flask中用于操作关系型数据库的扩展…