1. 对传入的Lock参数执行Release 2. 关中断 3. 将当前线程加入conditionlist,当前线程Sleep 4. 对传入的Lock参数执行Acquire 5. 开中断 Signal函数: 1. 关中断 2. 如果conditionlist队列不为空,将队头线程取出,并放入ReadyToRun队列 3. 开中断 Broadcast函数: 1. 关中断 2. 将conditionlist队列中所有线程取出,并放入ReadyToRun队列 3. 开中断
性,当一个线程需要wait一个signal时,需要让出CPU。而在Nachos系统中,管程的互斥访问是由Lock保证的,为了防止死锁,需要在当前线程进入休眠之前释放lock。当线程再次被唤醒时,需要再次Acquire这把锁。 Signal函数即唤醒一个正在等待这个条件变量的线程。 Broadcast函数即唤醒所有正在等待这个条件变量的线程。 Exercise4:实现同步互斥实例
任务
基于Nachos中的信号量、锁和条件变量,采用两种方式实现同步和互斥机制应用(其中使用条件变量实现同步互斥机制为必选题目)。具体可选择“生产者-消费者问题”、“读者-写者问题”、“哲学家就餐问题”、“睡眠理发师问题”等。(也可选择其他经典的同步互斥问题) 完成情况
1. 基于Nachos信号量实现“生产者-消费者”问题
(基于时间片轮转调度,时间片长度随机。为了使得中断有可能在任何地方发生,在所有临界区中的代码语句后面都调用了interrupt->onetick) 修改情况: 新增测试变量和函数 测试变量: 1. isFull信号量,初始值为0 2. isEmpty信号量,初始值为N(N为生产者可以放入的最大数量,设为5) 3. M1信号量 4. 生产数组 Producer函数 1. isEmpty->P() 2. 在M1信号量保护下访问生产数组,加入一个元素 3. isFull->V() Consumer函数
简单解释 如果生产数组内元素数量达到N,则会被isFull信号量阻塞,生产者需要等待;如果生产数组内元素数量为0,则会被isEmpty信号量阻塞,消费者需要等待。 M1信号量用于保证生产数组的互斥访问。 由于IsEmpty信号量初始值为N,则生产者最多可以进入producer函数N次;相应的,isFull信号量会被释放至多N次 由于isFull信号量在生产者生产之后会被6
1. isFull->P() 2. 在M1信号量保护下访问生产数组,移出一个元素 3. isEmpty->V() Test_Producer函数 For循环40次,调用producer函数 Test_consumer函数 For循环40次,调用consumer函数 ThreadTest函数 新生成1个生产者线程(装载Test_producer函数)和2个消费者线程(装载Test_consumer函数)
测试结果截图:
释放,因此此时消费者可以消费。相应的,isEmpty信号量被释放,使得生产者可以继续生产。 生产者生产(至多)40次。(因为可以有多个生产者) 消费者消费(至多)40次。(因为可以有多个消费者) 生产者放入队列的元素 发生时间片中断,切换线程 两个消费者交替消费元素
2. 基于Nachos的条件变量实现“生产者-消费者”问题
(基于时间片轮转调度,时间片长度随机。为了使得中断有可能在任何地方发生,在所有临界区中的代码语句后面都调用了interrupt->onetick) 修改情况:
增改测试变量和函数 Synchlist.cc: 新增变量 1. ListEmpty条件变量 2. ListFull条件变量
简单解释 1和2同信号量部分的isEmpty和isFull语义 计数值用于判断生产队列是否满了 7
3. Listcount计数值 Append函数: 1. 加锁 2. 如果生产队列满,等待ListEmpty条件变量 3. 否则将新元素加入生产队列 4. Signal listFull条件变量 5. 解锁 加锁解锁保证管程函数执行的互斥性。 如果生产队列满,则等待消费者消费之后,发送listEmpty条件变量。 生产之后,发送listFull条件变量,激活等待消费的消费者 Remove函数 是Append函数的对偶版本。 1. 加锁 2. 如果生产队列空,等待listFull条件变量 3. 否则从生产队列头取出一个元素 4. Siignal listEmpty条件变量 5. 解锁 Monitor_producer函数 For循环40次,往Synchlist管程里的队列放入元素 Monitor_consumer函数 For循环40次,消费Synchlist管程里的队列的元素 ThreadTest函数 新生成1个生产者线程(装载Monitor_producer函数)和2个消费者线程(装载Monitor_consumer函数)
测试结果截图:
同test_producer 同test_consumer 两个消费者交替消费,并且不需要和生产者同步。
8
测试情况详细分析: 生产者加锁进入管程 放入第5个元素(最多为5) 发送isFull信号 解锁管程互斥锁 生产者试图继续加锁进入管程 (失败,由于生产队列满)释放管程互斥锁 进入等待isEmpty信号的状态(进入队列+sleep) 消费者1加锁进入管程 此时发生了中断 线程切换 消费者2试图加锁进入管程,但由于管程互斥锁此时在消费者1手中,因此消费者2继续等待
Challenge1:实现barrier
任务
可以使用Nachos 提供的同步互斥机制(如条件变量)来实现barrier,使得当且仅当若干个线程同时到达某一点时方可继续执行。 完成情况 增改处 Condition类: 1. 增加waitcount计数值,表示等待条件变量的队列中的线程个数 2. 增加Barrier函数,在函数中,判断waitcount是否达到规定值,如果达到,则广播所有队列中的线程;否则令当前线程进入等待状态 新增Barrier类: 仿照synchlist类,实现了一个互斥访问的管程。在管程函数里,调用barrier函数 测试函数: 新建3个线程,每个线程用for循环调用同一
简单解释 若还没达到规定值,则线程需要等待;若达到了,则释放所有等待线程。这样就可以使得规定值个数的线程“同步”运行 其中,规定值设为3 意图让线程均输出了i之后,再接着输出i+1 9
个Barrier类的函数10次 测试结果截图 未使使用Barrier
用
Barrier:
同步(三个线程均输出i之后才进入下一个,interrupt表示时间片到了切换线程。) 不同步
Challenge2:实现read/write lock
任务
基于Nachos提供的lock(synch.h和synch.cc),实现read/write lock。使得若干线程可以同时读取某共享数据区内的数据,但是在某一特定的时刻,只有一个线程可以向该共享数据区写入数据。
完成情况
(基于时间片轮转调度,时间片长度随机。为了使得中断有可能在任何地方发生,在
reader函数和writer函数所有的代码语句后面都调用了interrupt->onetick) 修改情况:
增改变量及函数 变量: Lock mutex Lock w 简单解释 Mutex用于保护共享变量rc(记录读者数量) W用于读者和写者访问临界区的互斥性 10