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

做网上夫妻去哪个网站咸宁网站开发

做网上夫妻去哪个网站,咸宁网站开发,传奇网站模板使用,蔷薇花园网站怎么做的在上一篇博客中#xff0c;我讲述了在多执行流并发访问共享资源的情况下#xff0c;如何 使用互斥的方式来保证线程的安全性#xff0c;并且介绍了Linux中的互斥使用的是 互斥锁来实现互斥功能#xff0c;以及它的原理#xff0c;在文章的结尾我提出了一个问题 用来引出同…在上一篇博客中我讲述了在多执行流并发访问共享资源的情况下如何 使用互斥的方式来保证线程的安全性并且介绍了Linux中的互斥使用的是 互斥锁来实现互斥功能以及它的原理在文章的结尾我提出了一个问题 用来引出同步的话题那么这篇文章我将会介绍同步的概念以及Linux中 的同步是如何实现的。1. 正式开始前的知识 a. 可重入和线程安全 我在前面提出过两个概念或者是名词那就是可重入/不可重入函数以及线程安全我说不可重入的函数在多执行流下被访问的话就会引发线程不安全问题因为一个函数可不可重入一般都会涉及到多执行流才会谈论这个话题那我们们来正式认识一下它们两个 线程安全多个线程并发同一段代码时不会出现不同的结果。常见对全局变量或者 静态变量进行操作并且没有锁保护的情况下会出现该问题。 重入同一个函数被不同的执行流调用当前一个流程还没有执行完就有其他的执 行流再次进入我们称之为重入。一个函数在重入的情况下运行结果不会出现任何 不同或者任何问题则该函数被称为可重入函数否则是不可重入函数。如何避免出现线程不安全的问题呢 这里给出几点建议 每个线程对全局变量或者静态变量只有读取的权限而没有写入的权限一般来说这 些线程是安全的 类或者接口对于线程来说都是原子操作 多个线程之间的切换不会导致该接口的执行结果存在二义性其实上面精炼一点就是对共享资源要保护好或者对共享资源只读不写如果要使用的话要保证原子性原子性的体现可以使用锁来实现。 而对于函数可不可重入则是会有这些现象 调用了malloc/free函数因为malloc函数是用全局链表来管理堆的 调用了标准I/O库函数标准I/O库的很多实现都以不可重入的方式使用全局数据结构 可重入函数体内使用了静态的数据结构以上情况的出现都会导致函数成为不可重入函数。 至此我们来认识一下重入与线程安全之间的关系 如果一个函数可重入那么这个函数在多线程下使用就是线程安全的如果不可重入 那么自然在多线程中使用这个函数当线程函数的话势必会导致线程不安全问题。他们两者的区别 1. 可重入函数是线程安全函数的一种 2. 线程安全不一定是可重入的而可重入函数则一定是线程安全的。 3. 如果将对临界资源的访问加上锁则这个函数是线程安全的但如果这个重入函数 若锁还未释放则会产生死锁因此是不可重入的。在上面的讲述中我提到了死锁这个名词。关于死锁的知识我们也是有必要认识的。 b. 死锁 死锁是指在一组进程中的各个进程均占有不会释放的资源但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。 这种现象一般出现在非常大的工程或者使用了非常多的锁的情况下比较容易出现只是使用一个锁的话是不容易出现死锁的问题的我来大致表述一下死锁如何出现 假设现在我们有两个线程并且有两个共享资源两个线程中都使用到了这两个共享资源既然要使用共享资源两个执行流就得对共享资源进行保护那就是互斥而在Linux中就是使用互斥量来保护 我们是有可能写出这种代码的。当两个线程开始并发运行的时候A线程先申请好mutex1B线程申请好mutex2然后A线程开始申请mutex2/ B线程开始申请mutex1这个时候两个线程就会相互阻塞。除却锁之外代码本身没有问题但问题就出在了锁资源的申请。两个执行流都已经获取了两个锁资源但是后续代码的执行还需要对方的锁资源而两个执行流又不释放自己的锁资源导致两个线程一直处于阻塞状态这就是死锁问题。 这里给出死锁产生的必要条件也就是当出现死锁问题时必定会有这几个问题的出现 1.互斥条件一个资源每次只能被一个执行流使用 2. 请求与保持条件一个执行流因请求资源而阻塞时对已获得的资源保持不放 3. 不剥夺条件:一个执行流已获得的资源在末使用完之前不能强行剥夺 4. 循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系那么避免死锁产生的问题就转化为了避免同时出现这四个情况中的一个就能够避免死锁的产生了。 当然要避免死锁问题最最粗暴的方式就是不使用锁因为锁的本质还是要保护共享资源嘛如果我们的代码能够支持资源能够给每个线程独享一份那么就不需要锁了。 避免死锁问题 1. 加锁顺序一致 2. 避免锁未释放的场景 3. 资源一次性分配2. 同步 a. 同步的提出 在上一篇博客中我最后引出了同步的话题现在我再次举一个例子来说明同步的必要性 假设我们现在有一个自习室这个自习室同一时刻只允许一个人进入。那么现在有一个叫小明的同学一大早就进入到了这个自习室去学习了一直学习到上午自习室外有一些同学也想进入自习室里学习但是现在小明在自习室里学习他们都进不去又过了一会儿小明学的烦躁得不行了想去外面放松一下。但是他一开门发现外面这么多学生都等着使用这个自习室小明想“我要是走了的话假如我想学习了再进这个自习室里又不知道是啥时候了”。所以小明又走进了自习室关上了门继续学习过了一两分钟小明实在不想学习了又走出自习室然后发现外面的人还是很多他又走了回去就这样小明进进出出如此往复小明在这个时间段中根本没有学习再说直白点他只是把这个门开了关关了开根本没有做有意义的事。然而外面的学生也一直学习不上。这就出现了问题 在这其中每个学生包括小明都是线程而自习室就是临界资源同时这个临界资源也是互斥的但是我们发现这些线程之后总体上来说什么事情都没干但是还运动了在计算机中小明就是一直申请锁释放锁重复这个步骤其他线程也因为无法竞争到锁资源而一直被阻塞这些线程也叫做饥饿线程这种问题也叫做饥饿问题。 学校知道了这件事情后就发出了相关规定当一个人从一个自习室出来之后这个人不能马上再次进入自习室而是排在所有等待进入自习室同学的最后面这样以此往复每个同学都能合理的在自习室中学习而不至于出现一个学生在自习室中只仅仅出出不做任何事情浪费资源。 这种让线程有顺序的访问共享资源的方式就是同步。 互斥保证了共享资源的安全而同步则是能够较为充分的使用资源 b. 生产消费者模型 1). 模型介绍 为了更好的认识同步我们也有必要先认识一些生产消费者模型。以现实的生活举例我们的生活中有生产者有消费者。假如现在有一个大型超市这个超市中生产者负责将物品运送到超市中而生产者负责拿走消耗物品 而这种模型在多线程中也有所体现供应商和消费者都是线程生产者线程负责提供资源到超市中消费者线程负责从超市中获取资源。那么超市无疑就是一段内存空间负责数据的存放它可以是一段堆空间也可以是一个队列等容器。 我们现在发现上图中线程的身份有两种那么它们之间的关系就有三种我们需要理清楚这三种关系 首先是生产者和生产者之间毫无疑问生产者和生产者之间是竞争关系而且当我在超市的一个区域中置放好货物之后其它供应商是不能再在这里放的这里行为在计算机中就是数据的覆盖这种行为是不被允许的。换句话说当我在置放货物的时候你是不能再置放货物的假设置放空间不大每个供货商要么放要么放满。那么由此观来生产者和生产者之间的关系在计算机中就是互斥。 其次是消费者和消费者之间这个也不难它们也是竞争关系在超市资源少的情况下可以体现出来也是互斥的。 而对于生产者和消费者之间 假如我们的供应商放置货物的步骤是放好货物然后拍张照记录工作结果但是当供应商放好货物之后还没来得及拍照消费者就把这个货物拿走了其中消费者还没等生产者共享资源的操作完成消费者就来访问共享资源导致供应商的工作出现了错误在计算机中这就是多执行流并发访问共享资源导致的数据不一致问题所以生产者和消费者之间是互斥的。 还有一种情况假如超市里面没有货物消费者第一次来了超市一看没有货物第二次看也没有然后如此往复一直看。上面说到生产者和消费者之间是互斥的。而现在生产者一直在看超市中有没有货物其实就是消费者一直在申请锁访问共享资源而且是无意义的然后再释放锁。这样会一直导致生产者无法将货物放置到超市中。这种现象就跟我上面同步的提出中面临的问题一样由于一个线程一直获取锁资源之后做无意义的事而其他线程也无法继续向后执行该线程也一直在浪费资源而这种现象的解决就需要同步所以生产者和消费者之间也应该是同步的。 2). 模型理解 这种模型在计算机中有什么用呢 我们现在有这么一段代码 可以发现这段代码是串行的这里是一个Add函数这个函数需要main函数传参给它然后它负责将结果返回。这个过程对与计算机来说是很快的但是假如这个Add函数其中的逻辑很复杂执行一次Add函数需要的时间很多呢而main函数中除却Add函数之外其它的代码执行的都很快这就需要用到我们的生产者消费者模型了。 在生产者消费者模型中调用Add函数的一方明显就是生产者线程而执行Add函数的也就是消费者线程。如果这样实现的话那么我们生产者代码的执行时间就与Add函数无关了假如不关心返回值提高了生产者代码执行的效率支持忙闲不均而且实现了多执行流之间的一个解耦。 c. 条件变量的介绍 Linux中同步实现的方式是条件变量。 经过上面的认识我们知道在多线程并发访问共享资源的情况下互斥只能保证资源的安全但是只有互斥的话会出现某一个线程一直申请锁 释放锁的无效的事情浪费资源从而产生饥饿问题所以就需要同步来防止这现象的发生。 那么在上面介绍生产者消费者模型中生产者和消费者之间的关系中的同步的提出中这种无意义的浪费资源的现象的本质其实是资源就没有准备好所以同步也是当临界资源没有准备好之后阻止线程继续无意义的申请锁释放锁浪费资源因为锁也是资源。 而且同步也能保证线程的执行具有一定的顺序性而不是一个线程一直获取锁资源而其他线程处于饥饿状态。 经过上面的总结我们可以大概认识条件变量中为了防止线程一直因为资源没有准备好而一直无意义的获取锁资源的行为条件变量中需要有一个字段来表示资源是否已经准备好。 为了保证线程执行的有序性它也必须维护一个线程的队列。 d. 条件变量的使用 那我们就来介绍Linux中是如何实现同步的。 我在之前就提过这个问题这里打印出现错误的原因是屏幕也是共享资源。 这里我们对打印的过程加锁就不会再出现了 但是我们发现它们的打印顺序可以说是没有规律的。这里我们就可以使用条件变量来让它们的打印有序在此之前我们先要认识一下接口 以上是一个条件变量的初始化内容和我们的互斥量有些相似。 将条件变量初始化好之后我们还要能让线程在条件变量中排队 pthread_cond_wait可以将调用它的线程放入条件变量的等待队列中可以看到它的第二个参数是一把锁这个会在之后的使用中来解释直到条件变量被唤醒 其中pthread_cond_signal可以唤醒一个条件变量。 我们现在来使用一下这些接口来让上面的代码执行有序 可以看到线程的打印确实一直是同一个顺序了。上面还有一个接口没有介绍pthread_cond_broadcast。pthread_cond_signal是唤醒一个线程而pthread_cond_broadcast是唤醒所有线程 这里看着跟上面一样但其实上面的打印是一行一行的打印逐一唤醒线程而这个是三行三行的打印唤醒所有线程。 上面的代码中我们只展现了条件变量能一定程度上控制线程执行的顺序但是条件变量还有一个作用就是防止共享资源在没有准备好的时候线程一直申请锁释放锁浪费资源。上述代码无法体现的原因是没有直观的共享资源来体现。 而且现在也滋生出了几个问题 我们发现条件变量的等待是在临界区中的条件变量被唤醒之后继续向后执行的也是临界区的代码。要知道当一个线程被条件变量等待之后它也是带着锁资源等待的。那么当一个线程条件变量等待之后其他线程在干什么当条件变量等待的线程被唤醒之后继续执行临界区的代码的时候其他线程在干什么难道是一直被阻塞在等待锁资源的那一步吗那么为什么要申请条件变量啊这些问题当我们给出下面的代码或许能够更好的解释这些问题 现在我们模仿上一篇博客中的抢票代码并做一些小修改 ** 我们首先看到的就是抢票的线程它并没有按照一定的顺序执行抢票。并且当g_ticket不大于零时所有线程都在打印“没有票了”打印这句话背后的含义是什么呢那就是这些线程根本没有做任何有意义的事因为g_ticket已经没有了临界资源未准备好而只是一直申请锁释放锁做这种浪费资源的事情所以才会有条件变量的出现这里我们要使用条件变量就应该是不要让在票没有了之后还让线程一直做无用的浪费资源的事情 这些线程就会被阻塞了。 但是这些线程现在一直在等待等待资源是否已经准备好那么我现在再对代码做一下修改我们每过一段时间就补充一定数量的票然后再让这些线程进行争抢 我们也可以在票没有了之后只唤醒一个线程 当你执行过这段代码之后你就会发现出了第一次抢票外后续整体的抢票都是有一定顺序的。 现在我就来解释一下上面的一些现象   为什么条件变量在临界区中让线程进入等待之后能够让线程保证一定的顺序性我又说条件变量中有一个队列来保证这个现象但是要知道条件变量让线程等待的时候该线程可是携带者锁资源等待的其他线程此时根本不能够进入临界区何来让线程在条件变量下等待啊   所以我在这里给出当条件变量让线程进行等待时该线程会释放所资源这也是为什么pthread_cond_wait的第二个参数会有一把锁了。   还有一个问题现在能够实现线程进入临界区之后执行到让线程等待的条件变量的代码的时候能够排队直到临界资源准备好再让固定线程唤醒就好了但是这里当我们唤醒所有线程的话又不是乱套了吗假如唤醒后线程仍会执行共享资源的访问那么此时线程就是不安全的了   这里也给出解释当在条件变量下等待的线程被唤醒后返回时会重新参与到锁资源的竞争中并不会直接执行后续的代码。这一点也保证了互斥的原则假如没有这一点的话我们知道线程在条件变量下等待同时会释放锁资源假如临界区外的线程获取到锁资源进入临界区之后等待的线程同时也被唤醒这样也会导致多个线程同时出现在临界区中也违反了互斥的概念。 3. 生产消费者模型 经过上面对同步的认识以及生产消费者模型的介绍我们知道要实现生产消费者模型其实也就是保证两种身份之间的三种关系就能很好的保证共享资源的安全性了也就是保证线程安全了。 a. 阻塞队列 我们现在来通过阻塞队列来实现一下单个生产者消费者的模型阻塞队列是什么呢其实也很简单就是当阻塞队列中为空时消费者进程会被阻塞知道生产者将数据放到阻塞队列中当阻塞队列中为满时生产者线程会被阻塞直到消费者线程让阻塞队列不在是满的。 b. 阻塞队列的实现 那么我们现在就来实现 我们需要封装一下STL中的队列因为STL中的容器大部分方法都是不可重入函数。而且我们这个阻塞队列中可能存任意类型的数据int、float等等所以使用模板。 上面说到阻塞队列是有容量的并且生产者和消费者之间是互斥且同步的并且生产者和消费者之间是能够互相阻塞的所以这里需要两个条件变量以让两者能够互相阻塞以能够实现同步 接下来就是具体方法的实现 这样我们的一个比较简单的生产消费者模型就完成了我们现在来试用一下 我们也可以让生产者先充满阻塞队列然后再让消费者消费数据 可以看到我们确实可以通过条件变量来实现控制线程执行的顺序。 c. cp模型的再理解 上面的代码实际上是不够健壮的我们来看这里 这里会有一定的问题出现。现在我们是单个的生产者消费者如果是多个的呢假如有多个消费者线程都在条件变量下等待此时生产者插入了一个数据我们现在假如是唤醒所有的消费者线程那么此时所有的消费者线程全部开始锁资源的竞争第一个竞争到的消费者线程能安全的把代码执行完假如这个时候生产者并没有产生数据而第一个消费者线程已经执行完临界区代码后释放锁这时第二个解除等待的消费者线程竞争到锁资源继续执行_q.pop()这个时候队列中可是空的啊那么势必第二个消费者线程执行到这里的时候程序就会报错。所以这里会产生伪唤醒的现象出现。 解决方式也很简单 if改while; 这样就能有效地解决了。也提高了代码的健壮性。 我们在上面对阻塞队列存储的内容是int那可不可以是一个任务呢 这个任务可以是从网络上传输过来的也可以是本地的完全自主设计。 现在可以看到生产者消费者模型确实是可以支持代码的解耦生产者生产时消费者也可以消费但是生产者消费者可以提升解决任务的效率又是从何而来呢可以看到两种角色两两之间都是互斥的这意味着当某一个角色执行任务访问共享资源时同身份的其它线程和另一个身份的线程都会被阻塞而阻塞也就意味着串行何来提高效率这一说呢 关于这个问题的理解我们不应该在模型本身而是应该放在生产者的数据是怎么来的消费者消费数据以及消费数据之后该怎么做。要知道生产者获取数据以及消费者收到执行什么任务之后开始执行任务这些事情可都是并行的了所以这里才是生产消费者提高效率的真正原因。 上述代码我说的是单生产单消费模型多生产多消费呢难道要在线程函数上再上两把锁吗生产者与生产者之间互斥消费者和消费者之间互斥其实不是的关于线程的互斥并不是对于线程来说的而是对于资源来说在整个生产消费者模型中使用的共享资源只有一份那就是阻塞队列。所以只需要一把锁就可以。而我们代码中的锁正好就是在临界区上所以我们的代码本来就是支持多生产多消费的
http://www.w-s-a.com/news/510671/

相关文章:

  • wordpress证书关闭重庆seo优化效果好
  • 直播网站建设模板网站活动怎么做的
  • 医院网站建设网站网站开发工资高嘛
  • 个人网站备案内容写什么做网站是不是涉及很多语言职
  • 怎么用手机做一个网站门户网站建设工作的自查报告
  • 网站搭建怎么收费浙江建设集团网站
  • 建网站怎么赚钱免费引流软件下载
  • 自建网站服务器备案做基础销量的网站
  • 淘宝 网站建设 发货音乐网站首页设计
  • 丽水做网站杭州建电商网站多少钱
  • 建设网站能解决什么问题wordpress 模板 中文
  • 平台型网站建设预算表友情链接中有个网站域名过期了会影响
  • 漯河网站开发运营seo是什么意思
  • 网站建设的征求意见稿iis 网站 红
  • 网站搭建教室企业网站开发实训心得
  • 阿克苏建设网站佛山app定制
  • 做淘宝网站要求与想法大型网站建设推荐
  • 在百度做网站赚钱吗跨境电商网站开发
  • 酒店网站建设策划方案南昌网站建设南昌
  • 临沂罗庄做网站房产cms
  • 五合一网站做优化好用吗网站设计的专业流程
  • 毕业设计论文网站开发需要多少网站seo建设方案
  • h5页面用什么做杭州优化外包哪里好
  • 许昌网站建设百姓国货app下载
  • 什么是建站装修公司做宣传在哪个网站
  • 阿里云虚拟主机多个网站吗大庆油田建设集团网站
  • 坂田公司做网站公司有网站域名后如何建网站
  • 自媒体网站程序淘宝网站维护
  • 凡科网站建设网站wordpress 七牛oss
  • 搬瓦工的主机可以用来做网站吗分类信息网站开发需求方案