初识Linux · 线程同步

目录

前言:

认识条件变量

认识接口

快速使用接口

生产消费模型


前言:

前文我们介绍了线程互斥,线程互斥是为了防止多个线程对临界资源访问的时候出现了对一个变量同时操作的情况,对于线程互斥来说,我们使用到了锁,而加锁的过程是原子性的,所以不用担心时间片轮转的时候发生错误,那么加锁的过程为什么是原子的我们也介绍了,因为加锁用到了cpu指令集中的swap指令,直接将内存中的值和寄存器中的值切换,只有一个汇编语句,所以是原子的。

以上是对于线程互斥部分的一个简单总结,本文,我们来介绍线程同步。

介绍线程同步我们这样介绍,从一个生活的简单例子入手,引出条件变量,然后快速的认识条件变量的接口,编写一段测试代码快速使用一下条件变量,最后的大头是生产消费模型,编写完生产消费模型,线程同步就完成了。

那么,进入主题吧!


认识条件变量

我们来假设这么一个场景:VIP自习室(只有一个人能使用),自习室的钥匙,多位同学。

其中的一位同学,从早上持有了自习室的钥匙,别的同学只能在自习室的门外等待该同学放回钥匙,终于,持有钥匙的同学出来放钥匙了,但是该同学又想继续自习,不想放钥匙,就刚把钥匙放下,就立马拿起来了,此时,其他同学刚有一点希望,就来绝望了。

这种情况是不合理的,因为其他同学无法获得钥匙,此时,我们将多个同学看作线程,钥匙是临界资源,所以就导致了饥饿问题。

所以为了合理性,对于钥匙的申请,就有了如下规定:

1->放下钥匙不能立马拿钥匙 2->第二次申请钥匙必须排队

所以,此时自习室的使用就有了一定的顺序性,我们将这种顺序性叫做线程的同步。

通过上文我们好像也没有引出来条件变量呀?

我们再来一个拿苹果的例子,A往盘子里面放苹果,B C从里面拿苹果,那么多个线程之间是独立的,它们怎么知道盘子里面是否有苹果呢?或者说,A怎么知道B C什么时候拿苹果呢?

此时需要一个铃铛吧?当A往盘子里面放了苹果,就敲一下铃铛,此时B  C正在排队,B在第一个,拿了苹果就到下一个了,此时顺序性有了,条件变量是什么呢?条件变量其实就是那个铃铛!!

可是,如果没有铃铛会怎么样呢?我们首先要认识到,苹果是临界资源没错,盘子也是吧?那么没有铃铛,就没有人告诉B是否有苹果没有,B就只能自己一直探测,可是一直探测的过程中就是对临界资源的持续访问,换句话说,A就一直访问不到盘子,也就放不到苹果,这效率不就非常非常低了吗?

认识接口

所以,我们需要引出条件变量,铃铛!现在我们对于铃铛有了基本的认识,那么来认识一下它的接口吧!

因为Ubuntu系统无法查看这一类函数,所以想要查看最好使用centos系统或者其他系统查看。

那么这里和互斥锁是十分十分相似的,条件变量分为局部的和全局的,如果使用的是全局的,我们只需要使用宏即可。

如果是局部的,势必要涉及到的函数是初始化和销毁,就是pthread_cond_init 和pthread_cond_destroy函数了,它们的参数也是十分简单的,第一个是pthread_cond_t类型的条件变量指针,第二个参数是属性,我们直接设置为空即可。

当然了,pthread_cond_wait从名字上就看得出来它是要某个线程等待的,至于参数为什么还有锁的参数我们先不管,后面自然会介绍到。

有了铃铛,我们总得敲响铃铛吧?对于函数pthread_cond_signal是唤醒单个线程的,对于函数pthread_cond_broadcast是唤醒在该条件变量下等待的所有线程的,参数也是非常简单,就是条件变量的指针而已。

以上是条件变量我们要使用到的接口,还是十分的简单的吧?


快速使用接口

#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>const int nums = 10;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void *wait(void *args)
{std::string name = static_cast<const char*>(args);while(true){pthread_mutex_lock(&mutex);pthread_cond_wait(&cond,&mutex);usleep(10000);std::cout << "I am " << name << std::endl;pthread_mutex_unlock(&mutex);}
}
int main()
{pthread_t threads[nums];// 创建多线程for (int i = 0; i < nums; i++){char *name = new char[128];snprintf(name, 128, "thread'name - %d", i + 1);pthread_create(&threads[i], nullptr, wait, (void *)name);usleep(10000);}// 唤醒线程while (true){pthread_cond_broadcast(&cond);std::cout << "thread wake up ... " << std::endl;sleep(1);}// 等待其他线程for (int i = 0; i < nums; i++){pthread_join(threads[i], nullptr);}return 0;
}

其实使用的话是没有多难的,和之前的互斥锁一模一样,不过是在这里开始我们慢慢的埋下了伏笔而已,比如pthread_cond_wait的第二个参数是什么意思

从上面的代码来说,我们能够理解线程等待的时候,通过函数pthread_cond_wait,在该条件变量下等待,其他的更多是复习了一下之前的内容而已。


生产消费模型

对于这么一个极其简陋的图来说,就是最简单的一个生产消费模型,其中表现的是我们平常都去超市买东西,那么超市是一个生产者吗?

显然,超市不是一个生产者,真正的生产者是供应商,也就是场景,那么消费者不必多说,问题在于,超市本身扮演的地位是什么呢?

实际上,对于超市来说,它更像一种缓冲区,因为消费者不可能买那么多东西,所以一般的模式是厂家给超市,超市给消费者,超市作为缓冲区可以囤积大量的货物。

那么如果没有了超市,会有什么结果呢?

如果没有了超市,消费者直接去厂家买,一次买几包,可是厂家光是打开机器的电都可以买几百包了,如果没有了超市,消费者每次都要和厂家联系,说我们要买什么什么,这样消费者和厂家的联系变的紧密了,是一种降低效率的紧密关系,如果没有了超市,一次性生产了多个商品,那完了,厂家可以下班了,因为消费者根本就买不了那么多东西

所以有了超市,可以让厂家和一次性生产许多,也不用担心下岗,因为有许多超市作为缓冲区放着,有了超市,可以让厂家和消费者解耦,因为有了中间媒介,既然有了中间商,那么就可以消费者一边消费生产者一边生产,效率也高,请注意,这里的效率也高和一边消费一边生产不是因为所以关系

那么,我们转接到线程部分来看待生产消费模型,一个一个的消费者和一个一个的生产者看成是一个一个的线程,那么我们可以将生产消费模型总结一下:

一个交易场所->超市

两个角色->生产者和消费者

三个关系->生产者和生产者,消费者和消费者,生产者和消费者

前两个我们是好理解的,那么三个关系我们应该如何理解呢?

生产者和生产者之间,也就是不同的厂家之间,这是竞争关系吧?都不用想,如果没有其他的厂家,只有一个厂家,那么该厂家不知道有多爽。所以生产者和生产者之间是典型的互斥关系

消费者和消费者之间,实际上也是互斥关系,为什么呢?平常是因为超市的东西足够,所以互斥关系不明显,如果哪天末日爆发,超市的东西有限,你看互斥关系会不会明显起来吧。

生产者和消费者之间,生产者生产好了给超市,消费者从超市里面拿数据,这就是一种顺序性,所以是一种同步关系,可是,如果超市没有东西了,消费者什么也拿不到,也就是对超市这个临界资源的访问必须暂停了,必须要等生产者生产东西给超市,此时消费者相当于就在条件变量下等待了,生产者生产了之后,登记货物的时候消费者也不能拿,必须等货物登记好了再拿,这不就是一种互斥关系吗?

那么实际上,我们面临的生产消费模型,不止有单生产单消费模型,还有多生产多消费模型。

在下篇文章中,我们就要介绍单生产单消费和多生产多消费的代码编写。

下篇文章涉及的是阻塞队列的生产消费模型和环形队列的生产消费模型。


感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 LlamaFactory 结合开源大语言模型实现文本分类:从数据集构建到 LoRA 微调与推理评估

文章目录 背景介绍文本分类数据集Lora 微调模型部署与推理期待模型的输出结果 文本分类评估代码 背景介绍 本文将一步一步地&#xff0c;介绍如何使用llamafactory框架利用开源大语言模型完成文本分类的实验&#xff0c;以 LoRA微调 qwen/Qwen2.5-7B-Instruct 为例。 文本分类…

【已解决】MacOS上VMware Fusion虚拟机打不开的解决方法

在使用VMware Fusion时&#xff0c;不少用户可能会遇到虚拟机无法打开的问题。本文将为大家提供一个简单有效的解决方法&#xff0c;只需删除一个文件&#xff0c;即可轻松解决这一问题。 一、问题现象 在MacOS系统上&#xff0c;使用VMware Fusion运行虚拟机时&#xff0c;有…

【教程】创建NVIDIA Docker共享使用主机的GPU

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 这套是我跑完整理的。直接上干货&#xff0c;复制粘贴即可&#xff01; # 先安装toolkit sudo apt-get update sudo apt-get install -y ca-certifica…

设备CTA进网许可认证有哪些值得注意的测试内容?

设备进网许可认证的测试项目与测试内容有哪些?在CTA进网认证过程中是否存在需要注意的地方?本篇是英利检测针对这两点给大家进行的资料整理&#xff0c;帮助大家更进一步了解项目难点所在。 一、电磁兼容测试(EMC测试) 电磁兼容测试旨在评估设备在电磁环境中的表现&#xff0…

flex布局容易忽略的角色作用

目录 清除浮动 作用于行内元素 flex-basis宽度 案例一&#xff1a; 案例二&#xff1a; 案例三&#xff1a; flex-grow设置权重 案例一&#xff1a; 案例二&#xff1a; 简写flex-grow:1 0 auto; 目录 清除浮动 作用于行内元素 flex-basis宽度 案例一&#xff1a…

vue自定义弹窗点击除了自己区域外关闭弹窗

这里使用到vue的自定义指令 <div class"item" v-clickoutside"clickoutside1"><div click"opencity" class"text":style"{ color: popup.iscitypop || okcitylist.length ! 0 ? #FF9500 : #000000 }">选择地区…

旧衣物回收小程序搭建,便捷回收,绿色生活!

随着人们生活水平的提高&#xff0c;各种衣物的更新速度逐渐加快&#xff0c;为了减少衣物的浪费&#xff0c;旧衣物回收市场受到了人们的关注。 如今&#xff0c;旧衣物回收行业的技术正在不断创新&#xff0c;利用科技的发展&#xff0c;结合了互联网的模式&#xff0c;提高…

自动驾驶数据集的应用与思考

数据作为新型生产要素&#xff0c;是数字化、网络化、智能化的基础&#xff0c;是互联网时代的“石油”“煤炭”&#xff0c;掌握数据对于企业而言是能够持续生存和发展的不竭动力&#xff0c;对于需要大量数据训练自动驾驶系统的企业而言更是如此。 而随着激光雷达、毫米波雷…

LLM - 01_了解LangChain和LangChain4J

文章目录 官网概述LangChainLangChain的核心功能LangChain的应用场景 LangChain4JLangChain4J的特点LangChain4J的应用场景 LangChain vs LangChain4J小结 官网 https://www.langchain.com/langchain https://docs.langchain4j.dev/ 概述 随着人工智能和自然语言处理&#…

文献补充材料怎么查找下载

最近很多同学求助问补充文献怎么查找下载&#xff0c;补充文献一般会在文献的详情页&#xff0c;参考文献的上面。需要注意以下这些词汇&#xff1a;Supplementary data、Supplementary material、Appendix、Supplementary Information、Appendix A. Supplementary data、suppl…

Redis(二)

Redis 事务 什么是 Redis 事务&#xff1f; 你可以将 Redis 中的事务理解为&#xff1a;Redis 事务提供了一种将多个命令请求打包的功能。然后&#xff0c;再按顺序执行打包的所有命令&#xff0c;并且不会被中途打断。 Redis 事务实际开发中使用的非常少&#xff0c;功能比…

Spherical Harmonics (SH)球谐函数的原理及应用【3DGS】

Spherical Harmonics &#xff08;SH&#xff09;球谐函数的原理及应用【3DGS】 前言球谐函数&#xff08;Spherical Harmonics, SH&#xff09;球谐函数不同阶的表达式以及有什么不同&#xff1f;具体介绍球谐函数基函数球谐函数 前言 高斯泼溅Gaussian Splatting (GS) GS 模…

spring boot之@Import注解的应用

我们知道spring boot会通过ComponentScan定义包扫描路径进行业务定义的bean的加载&#xff0c;但是对于很多不在此包路径下定义的bean怎么办呢&#xff1f;比如其他jar包中定义的。这时候import就发挥作用了&#xff0c;通过它也可以实现bean的定义。具体是怎么做的呢&#xff…

python数据分析之爬虫基础:requests详解

1、requests基本使用 1.1、requests介绍 requests是python中一个常用于发送HTTP请求的第三方库&#xff0c;它极大地简化了web服务交互的过程。它是唯一的一个非转基因的python HTTP库&#xff0c;人类可以安全享用。 1.2、requests库的安装 pip install -i https://pypi.tu…

linux安装docker和mysql

1.下载安装doker 1. 更新系统,确保系统是最新的 sudo yum update -y2.安装 Docker 所需的依赖包&#xff1a; sudo yum install -y yum-utils 2. 设置 Docker 仓库 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 3. 安装 Dock…

【MFC】vs2019中使用sqlite3完成学生管理系统

目录 效果图list Contral 控件的简单使用使用sqlite3 效果图 使用sqlite3完成简单的数据库操作。 list Contral 控件的简单使用 本章只介绍基本应用 添加表头&#xff1a;语法&#xff1a; int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat LVCFMT_LEFT…

Linx下自动化之路:Redis安装包一键安装脚本实现无网极速部署并注册成服务

目录 简介 安装包下载 安装脚本 服务常用命令 简介 通过一键安装脚本实现 Redis 安装包的无网极速部署&#xff0c;并将其成功注册为系统服务&#xff0c;开机自启。 安装包下载 redis-7.0.8.tar.gzhttp://download.redis.io/releases/redis-7.0.8.tar.gz 安装脚本 修…

mysql笔记——索引

索引 InnoDB采用了B树索引结构。 相比于二叉树&#xff0c;层级更少&#xff0c;搜索效率高。 B树中叶子节点和非叶节点都会存储数据&#xff0c;导致段页式存储中一页存储的键值减少&#xff0c;指针也会减少&#xff0c;要同样保存大量数据&#xff0c;只能增加树的高度&a…

AI大模型赋能医学诊疗与药学服务——课题基金申请辅导项目成功举办

2024年11月23日&#xff0c;北京整合医学学会在线上成功举办了“AI大模型赋能医学诊疗与药学服务——课题基金申请辅导项目”。此次会议吸引了来自全国各地的医学、药学及人工智能领域的专家学者和科研人员积极参与&#xff0c;共同探讨AI大模型在医学诊疗与药学服务中的应用&a…

【C语言】编译和链接总结

系列文章目录 &#x1f388; &#x1f388; 我的CSDN主页:OTWOL的主页&#xff0c;欢迎&#xff01;&#xff01;&#xff01;&#x1f44b;&#x1f3fc;&#x1f44b;&#x1f3fc; &#x1f389;&#x1f389;我的C语言初阶合集&#xff1a;C语言初阶合集&#xff0c;希望能…