nachos-java Task1.4 Communicator

来源:互联网 发布:dw制作淘宝首页 编辑:程序博客网 时间:2024/05/22 11:32

Task 1.4 Communicator

  • 实验要求
  • 实验关键代码
  • 关键代码分析
  • 实验测试代码
  • 测试结果分析

实验要求

◆ Implement synchronous send and receive of one word messages
– using condition variables (don’t use semaphores!)
– Implement the Communicator class with operations

• void speak(int word)

• int listen()

◆ speak() atomically waits until listen() is called on the same Communicator object, and then transfers the word over to listen(). Once the transfer is made, both can return

◆ listen() waits until speak() is called, at which point the transfer is made, and both can return (listen() returns the word)

◆ This means that neither thread may return from listen() or speak() until the word transfer has been made.

◆ Your solution should work even if there are multiple speakers and listeners for the same Communicator

实验关键代码

变量声明

Lock lock;private int speakerNum;private int listenerNum;private LinkedList<Integer> words;Condition2 listener;Condition2 speaker;

方法实现

关键代码是peak(int word)方法和listen()方法。

Void speak(int word)方法:

public void speak(int word) {    boolean preState = Machine.interrupt().disable();    lock.acquire();    words.add(word);    if(listenerNum == 0){        speakerNum++;        System.out.println("暂时没有收听者,等待收听");        speaker.sleep();        listenerNum--;    }else{         speakerNum++;         listener.wake();         listenerNum--;    }    lock.release();    Machine.interrupt().restore(preState);

Int listen()方法:

public int listen() {    boolean preState = Machine.interrupt().disable();    lock.acquire();    if(speakerNum==0){        listenerNum++;        System.out.println("暂时没有说话者,等待说话");        listener.sleep();        speakerNum--;    }else{        listenerNum++;        speaker.wake();        speakerNum--;       }    lock.release();    Machine.interrupt().restore(preState);    return words.removeLast();}

实验测试代码

private static class Speaker implements Runnable {    private Communicator c;    Speaker(Communicator c) {        this.c = c;    }    public void run() {        for (int i = 0; i < 5; ++i) {            System.out.println("speaker speaking" + i);            c.speak(i);            //System.out.println("speaker spoken");            KThread.yield();        }    }}public static void SpeakTest() {    System.out.println("测试Communicator类:");    Communicator c = new Communicator();    new KThread(new Speaker(c)).setName("Speaker").fork();    for (int i = 0; i < 5; ++i) {        System.out.println("listener listening " + i);        int x = c.listen();        System.out.println("listener listened, word = " + x);        KThread.yield();    }}

关键代码分析

思路分析

本实验编写程序并不难,重点在理解这个问题的本质:缓冲区为0的生产者消费者问题。说者说话只要有听者就交流成功,否则阻塞等待听者;听者听话只要有说者就交流成功,否则阻塞等待说者说话。

方法解释

1、Void Speak ( int word)方法

先申请锁,将说的话存放在words链表中,并将说者人数加1;然后判断是否有听者,如果没有,则说者睡眠;唤醒后要将听者人数减1;如果有听者,则将听者唤醒,然后将听者人数减1;记得最后将锁释放。

2、int listen()方法

先申请锁,将听着人数加1,然后判断是否有说者,如果没有,则听者睡眠,唤醒后要将说者人数减1;如果有,则将说者唤醒,并将说者人数减1;最后记得将锁释放,并返回words里一条信息。

关键点和难点

关键点:理解什么时候人数增加或减少。
每次说者讲话,不管有没有听者,说者人数先加一;减一操作在每次听者将说者唤醒之后;听者人数变化同理,每次听话,不管有没有说者,人数先加一,减一操作在每次说者唤醒听者之后。

难点:如何避免听者和说者在同时执行:可使用一把互斥锁。

测试结果分析

测试结果截图
这里写图片描述

测试结果分析

测试方法共使用两个线程,一个线程调用5次speak(int word)方法,另一个线程调用5次listen()方法,从而模拟了多个听者与说者的问题,从测试结果看,听者先听,发现没有说者,则听者睡眠;说者说话,唤醒听者,交流成功。

0 0