2017-08-31 37 views
3

通過閱讀golang src pipe.go來弄清楚管道是如何工作的,我跑到這兩個write()函數中去了()&。令我困惑的是,如果讀者調用read()func並保存l.lock然後等待數據,那麼writer如何調用write()func並獲取l.lock來寫入數據?io.Pipe Write()和Read()函數如何工作?

func (p *pipe) write(b []byte) (n int, err error) { 
    // pipe uses nil to mean not available 
    if b == nil { 
     b = zero[:] 
    } 

    // One writer at a time. 
    p.wl.Lock() 
    defer p.wl.Unlock() 

    p.l.Lock() 
    defer p.l.Unlock() 
    if p.werr != nil { 
     err = ErrClosedPipe 
     return 
    } 
    p.data = b 
    p.rwait.Signal() 
    for { 
     if p.data == nil { 
      break 
     } 
     if p.rerr != nil { 
      err = p.rerr 
      break 
     } 
     if p.werr != nil { 
      err = ErrClosedPipe 
      break 
     } 
     p.wwait.Wait() 
    } 
    n = len(b) - len(p.data) 
    p.data = nil // in case of rerr or werr 
    return 
} 

和讀:

func (p *pipe) read(b []byte) (n int, err error) { 

    // One reader at a time. 
    p.rl.Lock() 
    defer p.rl.Unlock() 

    p.l.Lock() 
    defer p.l.Unlock() 
    for { 
     if p.rerr != nil { 
      return 0, ErrClosedPipe 
     } 
     if p.data != nil { 
      break 
     } 
     if p.werr != nil { 
      return 0, p.werr 
     } 
     p.rwait.Wait() 
    } 
    n = copy(b, p.data) 
    p.data = p.data[n:] 
    if len(p.data) == 0 { 
     p.data = nil 
     p.wwait.Signal() 
    } 
    return 
} 
+1

我對sync.Cond瞭解不多,但有趣的是'p.rwait.L =&p.l'和'p.wwait.L =&p.l'。等待/信號對我有點不明白。 – captncraig

回答

2

互斥p.l在讀取用於寫sync.Cond條件,這將鎖定並根據需要解鎖。

調用Wait解鎖其鎖,並等待相應的Signal調用。您可以看到管道使用p.wwaitp.rwait來協調ReadWrite方法中的讀者和作者。

+0

非常好的捕獲。我終於意識到sync.Cond是非常適合挖掘這一點的。 – captncraig

+2

@ captncraig:是的,我覺得這個精確的管道代碼的簡化版本會爲同步包製作一個很好的Cond示例。 – JimB

+0

謝謝@JimB。我嘗試使用io.pipe將對象導出到AWS並將對象流式傳輸到AWS,並截斷了err數據。如果使用io.pipe輸出到本地文件,它將起作用。不知道爲什麼,因爲io.pipe write()func被阻塞,直到讀取器使用數據,這不會導致任何數據泄漏。 – NSTNF

相關問題