2015-11-03 91 views
1

我試圖創建一個程序使用2線程之間進行通信的管道(你可以說2線程之間的聊天),我的問題是當你寫有沒有問題,但是當我通過管道讀取消息時,我得到一個無限塊,並且我找不到合適的解決方案,因此所有收到的消息都會在控制檯中顯示出來。所以我試圖從線程1發送消息到線程2,它工作,但從線程2到1,有一個塊。Java管道,爲什麼我從管道讀取時無限期地被阻塞

我的程序是由3個班的,我將在下面告訴他們:

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(); 
} 
} 

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

和控制檯的結果總是像這

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" 
+0

無限塊不一定是死鎖。 – EJP

回答

1

從管道讀取被阻止,因爲它尚未關閉。這可能會工作:

public void receive() throws IOException { 

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

更新:我錯了這個足以。比較.read() == -1僅用於測試是否關閉了管道的另一側,並且收到了管道上的最後一個字符。測試.ready()是當時是否有任何字符在管道上。由於發送和接收都在兩個線程上,因此準備就緒不確定,並且如果在未準備好時停止閱讀,則可能會出現部分線路。

考慮到這一點,您需要一個不同的測試。我會附加每個消息與一個終結符令牌(例如0),然後期待在另一端。所以這是我測試過的一個解決方案:

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(); 
} 
+0

我用你的建議,我得到異常有關管道關閉 –

+0

管道關閉 產生java.io.IOException:管道在java.io.PipedReader.receive(來源不明)收盤 \t \t在java.io.PipedReader.receive(未知源) \t在java.io.PipedWriter.write(來源不明) \t在java.io.Writer.write(來源不明) \t在java.io.Writer.write(來源不明) \t在pipes1.Person .send(Person.java:53) \t at pipes1.Main $ 2.run(Main.java:52) \t at java.lang.Thread.run(Unknown來源) –

+0

它工作完美,真的很感謝你的兄弟 –