当前位置: 首页> 科技> IT业 > 做电影网站怎么赚钱_东莞建筑业协会官网_360优化大师下载_网站建设方案书 模板

做电影网站怎么赚钱_东莞建筑业协会官网_360优化大师下载_网站建设方案书 模板

时间:2025/7/11 18:17:50来源:https://blog.csdn.net/qq_55958734/article/details/144766203 浏览次数:0次
做电影网站怎么赚钱_东莞建筑业协会官网_360优化大师下载_网站建设方案书 模板

目录

同步的概念

条件变量 

条件变量的创建

初始化条件变量 

等待条件变量被满足 

唤醒等待

条件变量的销毁 

生产者消费者模型 


上期我们学习了线程的互斥,互斥是为了保证多个线程在访问临界资源时的合规性,本期我们将进一步学习线程的同步,同步则是为了保证多个线程访问临界资源的合理性。

同步的概念

在讲线程互斥时,我们曾经举了排队打饭的例子,知道了其实同步就是为了防止,一个线程持续的去访问临界资源,导致其它线程长时间无法访问到临界资源,造成其它线程的饥饿问题。所以为了避免这类现象的出现,我们提出了线程同步的概念。

同步:在保证数据安全的前提下,让线程按照某种特定的顺序依次访问临界资源,从而避免线饥饿问题,这种现象就叫做同步。

那么问题来了,我们使用互斥锁实现了线程的互斥,线程的同步该使用什么实现呢?这就又牵扯到了一个新的知识点,即条件变量。什么是条件变量呢?
条件变量,顾名思义,就是当条件达到时,就从阻塞队列中,唤醒一个正在阻塞的线程去访问临界资源。

条件变量 

条件变量与互斥锁的定义和使用都类似,但是条件变量的使用需要搭配互斥才能使用。

条件变量的创建

pthread_cond_t con;           //创建了一个条件变量

初始化条件变量 

  pthread_cond_init(&con,nullptr);          //条件变量的初始化,和互斥锁的初始化类似

等待条件变量被满足 

 pthread_cond_wait(&con,&mtx);          //等待条件变量被满足

唤醒等待

pthread_cond_signal(&con);           //唤醒一个在阻塞队列的线程

pthread_cond_broadcast(&con);          //唤醒所有在阻塞队列下等待的线程

条件变量的销毁 

   pthread_cond_destroy(&con);          //条件变量的销毁 

实例如下。我们创建了4个线程,1个主线程,3个分线程,主线程发送唤醒信号,3个分线程在条件变量下等待,分别唤醒1个线程和所有线程。 

整体代码如下。

#include<iostream>
using namespace std;
#include<pthread.h>
#include<unistd.h>//创建互斥锁和条件变量
pthread_mutex_t mtx;
pthread_cond_t con;//主线程唤醒条件变量下等待的线程
void* ctrl(void* args)
{const char* master=(const char*)args;while(true){cout<< "master say :begin work"<<endl;//一次唤醒1个线程// pthread_cond_signal(&con);//一次唤醒3个线程//pthread_cond_broadcast(&con);sleep(5);}}//分线程在条件变量下等待
void* work(void* args)
{int number=*(int*)args;while(true){pthread_cond_wait(&con,&mtx);cout<<"我是 "<<number<<"号线程"<<endl; }
}int main()
{
#define NUM 3//锁和条件变量的初始化pthread_mutex_init(&mtx,nullptr);pthread_cond_init(&con,nullptr);//创建主线程pthread_t master;pthread_create(&master,nullptr,ctrl,(void*)master);//创建分线程pthread_t worker[NUM];for(int i=0;i<NUM;i++){int* number=new int(i);pthread_create(worker+i,nullptr,work,(void*)number);}//线程等待for(int i=0;i<NUM;i++){pthread_join(worker[i],nullptr);}pthread_join(master,nullptr);//锁和条件变量的销毁pthread_mutex_destroy(&mtx);pthread_cond_destroy(&con);return 0;
}

运行结果如下。

当唤醒一个线程时。

当唤醒所有线程时。

我们通过运行结果不难发现,无论是一次唤醒1个线程还是一次唤醒所有的线程。所有的线程的执行都是顺序执行的,这正是因为,在条件变量下等待的所有队列都被加入了一个阻塞队列,一个线程在条件变量下被唤醒之后,执行完对应的代码再次去等待条件变量时,不能立即处于阻塞队列队头的位置,只能处于阻塞队列队尾的位置,所以这些线程代码的执行都是根据条件变量阻塞队列中,线程所处的位置依次去执行的。 

生产者消费者模型 

这个模型是对之前线程同步和互斥整体的应用。什么是生产者消费者模型呢?

超市大家都听说过吗?肯定听说过,超市是售卖东西的,但是超市售卖的东西是自己生产的吗,肯定不是,超市售卖的东西是,超市与相应的货物批发商合作,从批发商那里批发来的,批发来之后放在超市的柜台上,供顾客去选择。那么为什么顾客不能直接去批发商那里购买货物呢,当然是可以的,但是没必要。大多数的超市都是建立在人多的市中心的,批发商往往处于偏僻的位置,顾客可以去批发商那里购买货物,但是耗费的时间和精力是巨大的。而且大家试想这样一种情况,顾客去批发商那里购买货物,但是批发商那里还没生产出来,那么就会导致花费大量的时间去等到批发商生产出来,然后才能去购买。但是有了超市之后就不一样了,超市从批发商那里进货,顾客可以很轻松的在超市买到自己想要的物品,且即使超市对应的货物没有了,顾客也无需耗费大量的时间精力去批发商那里等待货物的生产并购买,直接在离自己比较近的超市等待即可,这样大大提高了效率。

综上其实,有了超市这个角色之后,实现了生产和消费的解耦(即生产和消费不直接打交道),大大提高了效率。这也是为什么超市的价格往往比批发商那里货物便宜的原因。通过图示进一步为大家展示。

不难发现在生产者和消费者模型中,有3中关系(竞争,互斥,同步),2个角色(消费者和生产者),1个场所(临界资源) ,生产者和消费者模型的目的就是实现生产者和消费者的解耦,提高效率。

基于阻塞队列的生产者和消费者代码实现。(这里的阻塞队列其实就是我们所说的临界资源,我们以当生产者和单消费者为例)

BlockQueue.hpp(hpp后缀的文件为类的声明和实现都在类中)

#include <iostream>
#include <queue>
#include <pthread.h>namespace blockqueue
{const int default_cap = 5;template<class T> class BlockQueue{public:BlockQueue(int cap = default_cap): _cap(cap){pthread_mutex_init(&_mtx, nullptr);pthread_cond_init(&_is_empty, nullptr);pthread_cond_init(&_is_full, nullptr);}~BlockQueue(){pthread_mutex_destroy(&_mtx);pthread_cond_destroy(&_is_empty);pthread_cond_destroy(&_is_full);}//producter 向阻塞队列中生产数据void push(const T& d){LockQueue();if (IsFull()){ProducterWait();}_bq.push(d);WakeConsumer();UnLockQueue();}//consumer 从阻塞队列中消费数据void pop(T* d){LockQueue();if(IsEmpty()){ConsumerWait();}*d=_bq.front();_bq.pop();WakeProducter();UnLockQueue();}private:std::queue<T> _bq; // 阻塞队列int _cap;          // 阻塞队列元素的上限pthread_mutex_t _mtx;pthread_cond_t _is_full;pthread_cond_t _is_empty;bool IsFull(){return _bq.size() == _cap;}bool IsEmpty(){return _bq.size() == 0;}void LockQueue(){pthread_mutex_lock(&_mtx);}void UnLockQueue(){pthread_mutex_unlock(&_mtx);}void ProducterWait(){pthread_cond_wait(&_is_empty,&_mtx);}   void ConsumerWait(){pthread_cond_wait(&_is_full,&_mtx);}     void WakeProducter(){pthread_cond_signal(&_is_empty);}void WakeConsumer(){pthread_cond_signal(&_is_full);}};}

CpTest.cc(生产者和消费者代码)

#include"BlockQueue.hpp"
#include<time.h>
#include<unistd.h>
using namespace blockqueue;void* producter(void* args)
{BlockQueue<int>* bq=(BlockQueue<int>*) args;while(true){int data=rand()%10+1;bq->push(data);std::cout<<"生产者生产数据 "<<data<<std::endl;}
}void* consumer(void* args)
{BlockQueue<int>* bq=(BlockQueue<int>*) args;while(true){sleep(2);int data=0;bq->pop(&data);std::cout<<"消费者消费了一个数据 "<<data<<std::endl;}}int main()
{srand((long long)time(nullptr));pthread_t c;pthread_t p;BlockQueue<int>* bq=new BlockQueue<int>();pthread_create(&c,nullptr,consumer,(void*)bq);pthread_create(&p,nullptr,producter,(void*)bq);pthread_join(c,nullptr);pthread_join(p,nullptr);return 0;}

运行结果如下。

通过现象不难看出,生产者在把阻塞队列中的数据生产满之后,消费者再消费,之后,消费者消费一个,生产者生产一个,生产者生产一个,消费者消费一个,依次循环,呈现了明显了顺序性,即使用互斥锁和条件变量,实现了生产者和消费者模型的同步。 

以上便是线程同步和同步的应用所有内容。

本期内容到此结束^_^

关键字:做电影网站怎么赚钱_东莞建筑业协会官网_360优化大师下载_网站建设方案书 模板

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: