问题描述:

i'm trying to create a program using pipes that communicate between 2 threads (you can say chat between 2 threads), my problem here is when you write there is no problem, but when i read message coming through a pipe i get an infinite block and i couldn't find the appropriate solution so all messages sent & received are shown in console. so i tried to send message from thread 1 to thread 2 and it worked, but from thread 2 to 1, there is a block.

my program is composed of 3 classes and i will show them below :

package pipes1;

public class Main

{

public static void main(String[] args) throws Throwable

{

Pipe p1 = new Pipe();

Pipe p2 = new Pipe();

Person alice = new Person("Alice",p1,"recieved, thanks","hi bob");

Person bob = new Person("Bob",p2,"hi alice","recieved, thanks");

Thread terminal1 = new Thread(new Runnable()

{

@Override

public void run()

{

try

{

bob.connection(alice);

bob.send(bob.getName()+":"+bob.getMsg1());

bob.recieve(alice.getName()+":"+alice.getMsg1());

bob.recieve(alice.getName()+":"+alice.getMsg2());

bob.send(bob.getName()+":"+bob.getMsg2());

bob.send("1 to 2\n");

bob.recieve();

bob.recieve();

bob.send("ack 1\n");

bob.closing();

}

catch (Throwable e)

{

System.out.println(e.getMessage());

e.printStackTrace();

}

}

});

//terminal of a

Thread terminal2 = new Thread(new Runnable()

{

@Override

public void run()

{

try

{

alice.connection(bob);

alice.recieve(bob.getName()+":"+bob.getMsg1());

alice.send(alice.getName()+":"+alice.getMsg1());

alice.send(alice.getName()+":"+alice.getMsg2());

alice.recieve(bob.getName()+":"+bob.getMsg2());

alice.recieve();

alice.send("2 to 1\n");

alice.send("ack 2\n");

alice.recieve();

alice.closing();

}

catch (Throwable e)

{

System.out.println(e.getMessage());

e.printStackTrace();

}

}

});

terminal1.start();

terminal2.start();

}

}

=========================================================================

package pipes1;

import java.io.IOException;

public class Person

{

private String name; //name of person

private String msg1;

private String msg2;

private Pipe pipe;

public String getMsg1()

{

return msg1;

}

public String getMsg2()

{

return msg2;

}

public Pipe getPipe()

{

return pipe;

}

public String getName()

{

return name;

}

public Person(String name,Pipe pipe,String s1,String s2)

{

this.name = name;

this.msg1 = s1;

this.msg2 = s2;

this.pipe = pipe;

}

public void connection(Person x) throws Throwable

{

pipe.getReader().connect(x.pipe.getWriter());

}

public void closing() throws IOException

{

this.pipe.getReader().close();

this.pipe.getWriter().close();

}

public void send(String m) throws IOException

{

this.pipe.getWriter().write(m);

this.pipe.getWriter().flush();

}

public void recieve() throws IOException

{

int data = this.pipe.getReader().read();

while(data!=-1)

{

System.out.print((char)data);

data = this.pipe.getReader().read();

}

System.out.println("");

}

public void recieve(String m) throws IOException

{

int i = 0;

while(i<m.length())

{

System.out.print((char) this.pipe.getReader().read());

i++;

}

System.out.println("");

}

}

=========================================================================

package pipes1;

import java.io.*;

public class Pipe

{

private PipedWriter writer;

private PipedReader reader;

public PipedWriter getWriter()

{

return writer;

}

public PipedReader getReader()

{

return reader;

}

public Pipe()

{

writer = new PipedWriter();

reader = new PipedReader();

}

}

=======================================================

and the result of console is always like this

Bob:hi alice

Alice:recieved, thanks

Alice:hi bob

Bob:recieved, thanks

1 to 2

// here comes the block , thread 1 can't get the message "2 to 1"

网友答案:

Reading from the pipe is blocking because it has not been closed. This will probably work:

public void receive() throws IOException {

    while(this.pipe.getReader().ready()) {
        int data = this.pipe.getReader().read();
        System.out.print((char) data);
    }
    System.out.println();
}

UPDATE: I was wrong about this being sufficient. The comparison .read() == -1 is only used to test whether the other side of a pipe closed, and the last character on the pipe was received. The test .ready() is whether any characters are on the pipe at that moment. Because the sending and receiving are on two threads, the readiness is indeterminate, and if you stop reading when it's not ready, you might get a partial line.

With that in mind, you need a different test. I would append each message with a terminator token (e.g. 0) and then expect that on the other end. So here is a solution that I've tested:

public void send(String m) throws IOException {
    this.pipe.getWriter().write(m);
    this.pipe.getWriter().write(0);
    this.pipe.getWriter().flush();
}

public void receive() throws IOException {
    while(true) {
        int data = this.pipe.getReader().read();
        if (data == 0) break;
        System.out.print((char) data);
    }
    System.out.println();
}

public void receive(String m) throws IOException {
    for (int i = 0; i < m.length(); i++) {
        System.out.print((char) this.pipe.getReader().read());
    }
    this.pipe.getReader().read(); // consume the terminator
    System.out.println();
}
相关阅读:
Top