nachos-java Task1.4 Communicator

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()方法,从而模拟了多个听者与说者的问题,从测试结果看,听者先听,发现没有说者,则听者睡眠;说者说话,唤醒听者,交流成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值