惠州营销网站制作,网站开发前后端技术,网站建设项目模板,市场营销怎么做推广引言#xff1a;
北京时间#xff1a;2023/8/2/12:52#xff0c;时间飞逝#xff0c;恍惚间已经来到了八月#xff0c;给我的第一感觉就是快开学了#xff0c;别的感觉其实没有#xff0c;哈哈#xff01;看着身边的好友网络相关知识都要全部学完了#xff0c;就好像…引言
北京时间2023/8/2/12:52时间飞逝恍惚间已经来到了八月给我的第一感觉就是快开学了别的感觉其实没有哈哈看着身边的好友网络相关知识都要全部学完了就好像它们工业革命都要完成了而我还在刀耕火种哈哈哈他们在高速发展阶段我还在休养生息哈哈哈不怕正所谓没有压力没有动力让压力来的再猛烈一些吧咱无所畏惧八月就是咱逆分翻盘之月舍我其谁冲冲冲这句话我好想在哪见过哈哈哈别笑我真的在很严肃的看待这件事。八月没有什么拓展内容本来还想着在暑假的时候提高一下自己的做题能力可惜现在连课都学不明白可能是当时无知以为自己时间很多也可能确实是我们自己没把握好反正现在不管那么多八月我们的目标就是将网络搞定。废话不多说进军网络之前我们还是先把有关系统方面的知识先给搞定今天就让我来看看基于信号量知识的生产消费模型吧 基于环形队列的CP问题
上篇博客由于时间原因这部分有关信号量接口实操的知识我们没有讲解来到该篇博客我们在重温生产消费模型的基础上来看看如何实现信号量对共享资源中资源数量控制的同时让多线程可以安全的访问共享资源吧
1.复习环形队列
为什么使用环形队列 在学习信号量时我们重点强调了为什么要学习信号量并且明白信号量分为二元信号量互斥锁和多元信号量信号量就是一个对共享资源中资源数量的预定机制结合当时我们没有使用信号量实现的生产消费模型我们可以发现使用和不使用信号量的区别在于共享资源中是否存在多个临界资源需要被控制。在之前学习有关BlockQueue队列的CP模型我们可以发现它并不存在多个临界资源所以我们是直接采用互斥锁和条件变量的形式对其进行同步机制控制也就是对那唯一的共享资源进行保护就行。而当我们今天想要实现一份有信号量知识的CP模型那么前提就是需要有多个临界资源而我们的环形队列就能很好的实现这一效果。
回顾环形队列相关的知识 明白了为什么要回顾环形队列之后此时我们正式来复习一下环形队列毕竟这块知识已经学习快一年了去年11月份学的并且当时出处茅庐虽然也写了博客但是当时的博客并没有非常用心所以这一块知识给我的感觉比较模糊该篇博客我们就来重点复习一下由于这部分知识属于初阶数据结构并不适合展开理解也就是相关代码实现我们不体现出来感兴趣的小伙伴可以参考我之前的代码实现所以这里我们重点复习一下有关环形队列的概念知识也就是环形队列的实现原理和特征。 我们都知道无论学习什么都是由浅入深由概念到实操如果一上来就是实操那么你只会感觉天昏地暗什么都听不懂好比之前我们在学习生产消费模型每个人的实操代码都有可能是不同的但是其中的原理生产者和消费者的三种关系是谁都不能改变的所有人都必须紧紧围绕这个原理来实现自己的CP模型。所以同理在数据结构中无论是那种数据结构它们本质的不同就在于设计原理不同所以你想要看懂一份某数据结构的代码前提就是你对该数据结构的设计原理了如指掌同理你想实现一份代码也是这个道理。现在就让我们来看看环形队列是由那些原理组成的吧
环形队列原理和概念 环形队列也叫循环队列本质是通过一个数组或者链表实现同理只要按照环形队列的特征来实现无论使用数组还是链表都没有太大区别最本质的区别还要归咎于数组和链表的区别也就是数组和链表各自的优缺点这里我不展开复习所以我们只要明白环形队列就是一个固定大小但可以重复使用的队列其最大的特征在于开辟空间存储数据时要多开辟一个空间无论是数组还是链表实现该空间用于解决环形队列最大的问题判空判满问题也就意味着我们在实现环形队列时用户如果想要一个可以存储 K10个数据的环形队列那么在环形队列内部new空间时就需要new K1个空间当然这一过程由于被封装的原因上层用户并不能体会到但是你下层代码为了实现这一功能你就必须这么做同理很多不看源码你无法理解的功能都是通过这种理念实现。所以我们根据这一特征此时就能明白如果环形队列是通过数组实现那么此时它就需要通过两个整形数据front和tail作为数组下标来控制队列的循环过程当(tail1) % (K1) front时就表示此时环形队列满了而如果我们的环形队列是通过链表来实现那么此时它就需要通过两个结点指针来控制队列的循环过程当tail-next front时表示环形队列满了。明白了这些知识之后对于环形队列的判空判满简直不要太简单明白了环形队列的判空判满对于环形队列剩余的知识当然也不要太简单总而言之 环形队列没什么重点重点就在于理解环形队列为什么叫做环形队列也就是如何实现对空间的循环使用。 取模运算a % b可用于获取到一个0~b-1之间的数常用于对数组越界和数组下标的控制。 2.正式进入CP问题
明白了上述有关环形队列知识的学习此时顺理成章正式进入有关信号量实操问题也就是我们一直说的使用信号量来控制生产消费模型的实现所以接下来我们就来看看如何让信号量控制环形队列中的临界资源吧
同理实操的前提是对相关知识概念非常清晰首先我们就来谈谈在环形队列中信号量是如何控制资源以及使用信号量实现生产消费模型的特征也就是基于信号量的生产消费模型的实现原理。此时我们明白对于生产者和消费者来说它们关注的资源是不一样的生产者关注的是环形队列也就是共享资源中的空间资源而消费者关心的则是共享资源中的数据资源也就是当我们把一整块共享资源划分为一份一份的临界资源时此时生产者和消费者之间关心的资源不同生产者关心的是该共享资源中可写入数据的空间数量而消费者关心的是生产者写入数据之后产生的数据数量。所以当我们有了这两个抓手之后信号量实现生产消费模型的问题我们就差不多搞定了因为我们已经将该生产消费模型中的信号量给找到了也就是将共享资源中的空间资源看做是生产者的信号量而共享资源中的数据资源看做是消费者的信号量结合之前学习的有关信号量的知识此时我们就知道只有当共享资源中还有未存储数据的空间此时才允许某个生产者线程去申请空间信号量调度器决定当获取到了空间信号量之后才能继续向后执行反之等待。只有当共享资源在生产者生产之后也就是共享资源中有数据资源时才允许某个消费者线程去申请对应的数据资源同理获取之后才允许向后执行。当然具体信号量是如何实现没有对应信号量资源时让线程发生等待这个由底层代码决定这里我们不关心同理我们只关心信号量的使用规则和相应的功能。
如何实现信号量的P/V操作 明白了上述对信号量实现生产消费模型的简易分析此时我们就知道在该生产消费模型中存在两个信号量一个是生产者的空间信号量一个是消费者的数据信号量那么此时问题又来了我们应该如何对这两个信号量进行控制呢当然对于信号量的控制本质就是使用我们上篇博客中谈到的sem_post接口和sem_wait接口也就是伴随信号量产生的P/V操作。首先肯定是要有两个不同的信号量来分别表示空间信号量和数据信号量当我们在实现代码时我们就可以定义为_space_sem和_data_sem然后通过信号量初始化接口sem_init进行初始化并且因为空间资源先天存在数据资源后天由生产者生产所以我们将_space_sem初始化为num环形队列大小决定_data_sem初始化为0。然后当多个生产者线程和消费者线程开始同时访问共享资源时因为空间信号量存在数据信号量不存在所以此时生产者线程可以分配到信号量调度器决定且对应空间信号量发生P_space_sem操作直到_space_sem数量为0生产者线程全部等待而消费者线程由于数据信号量天生不存在所以在生产者进行V_data_sem操作之前全部等待只有当_data_sem数量不为0此时消费者线程才可能分配到信号量且对应数据信号量发生P_data_sem操作完成消费之后同理进行V_space_sem操作将空间资源释放。从而如此以往循环往复的实现生产和消费。
注意 生产消费模型并不代表只有当生产者线程生产完成之后消费者线程才能消费从之前学习有关BlockQueue模型的生产消费模型我们也能看出无论是生产者还是消费者只要其抢到了锁并且符合条件变量那么它就可以执行只不过对于BlockQueue来说我们是使用同一把锁的形式来控制生产者和消费者之间的同步关系从而实现共享资源只能被生产者或者消费者其中一个线程执行而此时对于CircleQueue模型来说我们支持生产者和消费者同时访问共享资源但不支持它们同时访问该共享资源中的同一份临界资源从而实现同步关系。那么此时这个同步关系主要体现在哪里呢信号量会给你答案我们通过控制两个不同信号量之间的P/V操作来实现这一同步机制从空间信号量产生数据信号量这一个原理我们可以很好理解也就是只有当进行了生产者生产数据信号量才会增加消费者才能消费这一原理我们能很好的体会到生产者和消费者之间的同步关系。
3.完整代码实现
3.1 单生产单消费 但注意 上述代码只有在单生产单消费的场景下才能运行也就是如果想要在多生产多消费的场景下运行此时我们就要让多线程之间发生互斥当然也就是通过互斥锁来实现那么为什么呢首先明白虽然像上述这种类对象本质所有线程在访问该类中的接口时都会将该类的对象也就是上述对象给拷贝一份到自己的栈空间从而让该类中的接口看做是一个可重入函数接口但是由于此时我们对类对象c_step和p_step看成局部变量存在修改数据的行为所以此时线程之间就会因为竞态条件的发生造成数据的不确定性引发线程安全问题因此我们就需要使用互斥的方式来保护该类对象的安全。明白了这个原因之后此时下述进行加锁之后的代码就是我们要的多生产多消费代码如下代码所示
3.2 多生产多消费 最后明白无论是单生产单消费还是多生产多消费本质并没有说谁的效率更高并不是单纯的认为多生产多消费的效率就更高如想要实现多生产多消费就需要进行加锁操作对于加锁肯定是会浪费效率的并且由于多生产多消费那么多线程之间的上下文切换也会造成一定的效率损失所以具体使用多生产多消费还是单生产单消费是需要通过问题场景来决定的同理使用信号量和不使用信号量也需要具体问题具体分析。总而言之还是那句话CP问题最大的好处不在于生产者和消费者之间的串行执行过程而是在于线程间的解耦和并发问题也就是之前说过的线程在等待期间无论是信号量、互斥锁它可以访问其它资源无论是否为共享资源从而让系统内部的资源利用率提高从而增强系统的响应速度。
总结该篇博客有关信号量实操相关的知识也就是基于信号量的CP问题我们就搞定啦并且有关多线程相关的知识我们就要学完了下篇博客应该就是我们对多线程知识的最后一篇博客当然也就是有关系统编程相关知识的最后一篇博客网络我来啦See you