英文:
How do the io.Pipe Write() and Read() functions work?
问题
通过阅读golang的源代码pipe.go,我想弄清楚管道(pipe)是如何工作的,然后遇到了这两个write()和read()函数。让我困惑的是,如果读取器调用read()函数并持有l.lock,然后等待数据,那么写入器如何调用write()函数并获取l.lock来写入数据呢?
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
}
and read:
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
}
这段代码中,通过使用锁来实现一次只能有一个写入器或读取器访问管道。在写入器的write()函数中,首先获取写入锁p.wl,然后获取管道锁p.l。如果发生错误或管道已关闭,会返回相应的错误。然后将数据写入管道,并通过p.rwait.Signal()通知读取器有数据可用。之后,通过循环等待读取器读取数据,直到数据被读取完或发生错误。
在读取器的read()函数中,首先获取读取锁p.rl,然后获取管道锁p.l。通过循环等待数据可用,直到数据被写入或发生错误。然后将数据从管道中复制到给定的缓冲区b中,并更新管道中的数据。如果数据已经全部读取完,则通过p.wwait.Signal()通知写入器可以继续写入数据。
这样通过使用锁和条件变量,实现了管道的读写同步和互斥访问。
英文:
By reading golang src pipe.go to figure out how pipe works, I ran into these two write() & read() functions. What confuses me is that if reader calls read() func and hold l.lock and then waiting for data, how does writer call write() func and acquire l.lock to write data in?
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
}
and read:
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
}
<!-- end snippet -->
答案1
得分: 2
互斥锁p.l
在读取和写入sync.Cond
条件中使用,根据需要进行锁定和解锁。
在条件上调用Wait
会解锁其锁,并等待相应的Signal
调用。你可以看到管道在Read
和Write
方法中使用p.wwait
和p.rwait
来协调读取器和写入器。
英文:
The mutex p.l
is used in the read and write sync.Cond
conditions, which will lock and unlock it as necessary.
Calling Wait
on the condition unlocks its lock, and waits for a corresponding Signal
call. You can see that the pipe uses p.wwait
and p.rwait
to coordinate the readers and writers within the Read
and Write
methods.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论