流水线

深入浅出计算机组成原理:冒险和预测(三):CPU里的“线程池”(第24讲)

北战南征 提交于 2019-11-29 00:38:24
一 、引子 过去两讲,我为你讲解了通过增加资源、停顿等待以及主动转发数据的方式,来解决结构冒险和数据冒险问题。对于结构冒险,由于限制来自于同一时钟周期不同的指令, 要访问相同的硬件资源,解决方案是增加资源。对于数据冒险,由于限制来自于数据之间的各种依赖,我们可以提前把数据转发到下一个指令。 但是即便综合运用这三种技术,我们仍然会遇到不得不停下整个流水线,等待前面的指令完成的情况,也就是采用流水线停顿的解决方案。比如说,上一讲里最后给你的例子, 即使我们进行了操作数前推,因为第二条条加法指令依赖于第一条指令从内存中获取的数据,我们还是要插入一次NOP的操作。 那我们能不能让后面没有数据依赖的指令,在前面指令停顿的时候先执行呢? 答案当然是可以的。毕竟,流水线停顿的时候,对应的电路闲着也是闲着。那我们完全可以先完成后面指令的执行阶段。 二、填上空闲的NOP:上菜的顺序不必是点菜的顺序 之前我为你讲解的,无论是流水线停顿,还是操作数前推,归根到底,只要前面指令的特定阶段还没有执行完成,后面的指令就会被“阻塞”住。 但是这个“阻塞”很多时候是没有必要的。因为尽管你的代码生成的指令是顺序的,但是如果后面的指令不需要依赖前面指令的执行结果,完全可以不必等待前面的指令运算完成。 比如说,下面这三行代码。 计算里面的 x ,却要等待 a 和 d 都计算完成,实在没啥必要。所以我们完全可以在 d

Stream:流水线

梦想的初衷 提交于 2019-11-28 22:46:29
Stream : 流水线 流水线 : 对数据的一组操作 jdk8,添加了新的类 java.util.Stream : Java8中的Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利高效的聚合操作,或者大批量数据操作 Stream的API结合Lambda表达式,极大的提高编程效率和程序可读性 同时它提供串行和并行两种模式进行操作 流操作 java.util.stream.Stream中的Stream接口定义了许多操作。 它们可以分为两大类。 ==1,中间操作 ==: 可以连接起来的流操作 2,终端操作 : 关闭流的操作 终端操作 会从流的流水线生成结果。 其结果是任何不是流的值,比如ListInteger,甚至void。 注:除非流水线上触发一个终端操作,否则中间操作不会执行任何处理。 使用流 流的使用一般包括三件事: 1,一个数据源(如集合)来执行一组操作; 2,一个中间操作链,形成一条流的流水线; 3,一个终端操作,执行流水线,并能生成结果。 ==工具类:Collectors == java.util.stream.Collectors 类 主要作用就是辅助进行各类有用的操作。 eg: 把Stream中的元素进行过滤然后再转为List集合 List list = Arrays.asList(“test”,“hello”,“world”

生产者消费者模型中的一点小问题

浪子不回头ぞ 提交于 2019-11-26 10:23:13
考虑以下这种情形: 目前有若干个消费者,一个生产者,现在流水线队列中已满,生产者在: MutexLockGuard lock(m_mutex); while(isFull()) notFull.wait(); 生产者在notFull.wait()中陷入阻塞。 此时某个消费者拿走了一个产品,并通过notFull.notify()通知生产者队列未满,可以生产。 生产者从wait中醒来,再次竞争锁。 但很不幸,这个锁再次被另外一个消费者获得。 一直持续这样的流程,生产者点太背,一直未获取到这个锁,直到最后一个消费者又先抢到了这个锁。 此时,根据队列的情况分为两种情况: a).如果队列还未空,这个消费者从队列中拿走产品并释放锁后,生产者终于拿到了这个锁,并往流水线中增加产品。 b).如果队列未空,这个消费者在通过while,进去notEmpty.wait()。在notEmpty.wait()内部,首先释放这个锁,然后陷入阻塞,这时生产者才再度拿到这个锁。 pthread_cond_wait()函数内部的机制就是: 1)释放锁 2)陷入阻塞 3)被唤醒后去竞争这把锁 1)的存在保证了该线程在阻塞前释放临界区给其他线程去竞争,不然若带着锁陷入阻塞,则这个生产者将得不到锁而无法增加产品,也无法notify这个带锁的消费者,进而形成死锁。 条件变量的作用在于