2017-08-31 34 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

相关问题