On Viernes 19 Diciembre 2008, Rudi Schlatte wrote:
> On 19.12.2008, at 20:33, Gábor Melis wrote:
> > On Viernes 19 Diciembre 2008, Tim Cooijmans wrote:
> >> I have two threads that communicate through a two-way pipe. This
> >> mostly works, but sometimes I get weird buggy behaviour, where
> >> something that's written into the pipe comes out twice at the
> >> other end.
> >>
> >> Attached is a minimal test case. The main thread reads from stdin
> >> and prints whatever is read to a pipe. The other thread reads
> >> from the other end of the pipe and prints whatever comes out.
> >> Feed it some input and you might see the second thread read the
> >> same input twice.
> >>
> >> What could cause this? My code looks good to me. Thread-safety
> >> shouldn't matter because the threads never read from or print to
> >> the same streams simultaneously (right?). Can anyone reproduce
> >> this or is it just me?
> >>
> >> Thanks,
> >>
> >> Tim
> >
> > I think it ought to be fine, however it fails here, as well.
> >
> > The root of the problem is that the two way stream itself will, for
> > some
> > reason, flush its OUT each time its IN is read (!), hence the
> > internal buffer is modified concurrently by two threads.
> >
> > One might think that passing :buffering :none to make-fd-stream as
> > it's
> > normally done makes the buffering problem go away, but it's not the
> > case as :buffering :none is implemented as "write to the buffer and
> > flush it immediately".
> >
> > Attached is a version of the test does not require user input and
> > stops
> > upon detecting the problem. Also, it uses only a single pipe.
> >
> > Removing the flush of OUT in two-way-stream when it's read solves
> > this issue for me:
> >
> > diff --git a/src/code/stream.lisp b/src/code/stream.lisp
> > index bd7086c..ceebf1a 100644
> > --- a/src/code/stream.lisp
> > +++ b/src/code/stream.lisp
> > @@ -939,7 +939,6 @@
> >
> > (macrolet ((in-fun (name fun &rest args)
> > `(defun ,name (stream ,@args)
> > - (force-output (two-way-stream-output-stream
> > stream)) (,fun (two-way-stream-input-stream stream) ,@args))))
> > (in-fun two-way-in read-char eof-error-p eof-value)
> > (in-fun two-way-bin read-byte eof-error-p eof-value)
> >
> > This piece of code comes from CMUCL. Does anyone know what is the
> > purpose of it?
>
> Code duplication from file streams, perhaps - flushing dirty output
> buffers before reading is the easiest way to avoid getting old data
> or overwriting dirty buffers with data from the file (i.e. data loss)
> in seekable streams. Of course, with non-seekable streams (pipes /
> sockets etc) this is not necessary, and in your case apparently
> harmful.
>
> Rudi
Thanks, committed as 1.0.24.1.
|