The problem with that theory is that ReadBuf will not activate when
FBufferSize is 0, which it is after DeleteBuffers during a Seek.  So a
WriteBuf must be executed first before a ReadBuf will do anything.
Therefore they should always be accessing different buffers.

Thanks,
Ross.

-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf
Of Wu Adam
Sent: Sunday, 5 August 2007 7:09
To: [email protected]
Subject: RE: Threading issue

I think there is a synchnization issue in your code as you assume  WriteBuf
and  ReadBuf will *always work on different buffers. The seek operations
caused the AV error becuase of this line:

>   FWriteBuf := FReadBuf;

Although this line is within two critical sections, but by the time seek
function returns, both critical section can be entered, so there is a small 
window that both   WriteBuf and  ReadBuf can start working on their own, 
and they race on the same buffer!


.dlrow eht htiw thgir s'lla ,nevaeh sih ni si doG





>From: "Ross Levis" <[EMAIL PROTECTED]>
>Reply-To: Borland's Delphi Discussion List <[email protected]>
>To: "'Borland's Delphi Discussion List'" <[email protected]>
>Subject: Threading issue
>Date: Sat, 4 Aug 2007 18:05:35 +1200
>
>Here's a problem to stretch the brain for those inclined.
>
>I have implemented an audio buffering system using linked memory buffers
>(Patent Pending - just joking).  The basic code is below.  WriteBuf is
>called by the audio decoder in an independent thread, and read in a 
separate
>thread in ReadBuf.
>
>WriteBuf allocates new memory space for a new buffer, and ReadBuf function
>frees the memory after it's read.  ReadBuf can ask for a different amount 
of
>data than that written.
>
>There is a buffer size limitation not shown, so memory does not blow out.
>
>The code as written produces an access violation occasionally when using 
the
>Seek procedure below.  The crash appears to always be in the memory 
manager
>code and either in a memory allocation routine or in a memory freeing
>routine.
>
>The Seek procedure is executed from a 3rd thread.
>
>No crash occurs when placing the same critical section around the read and
>write code but I don't understand why it's required.  The read and write
>routines should be accessing different memory buffers at all times, and 
this
>seems to be the case when no seek is done.  It all works fine.
>
>A read cannot occur until FBufferSize is incremented above zero meaning at
>least one block has been created.  So again, I can't understand why it's
>crashing.
>
>I'm trying to avoid placing the same critical section around the read and
>write routines to allow them to work freely and as fast as possible,
>particularly when initially buffering.
>
>Can anyone see anything obvious?
>
>
>type
>   PBufRec = ^TBufRec;
>   TBufRec = Record
>     Buffer: PByte;
>     BufSize: Integer;
>     NextRec: PBufRec;
>   end;
>
>var
>   FReadBuf,FWriteBuf: PBufRef;
>   FBufferSize: Integer;
>
>// Initialize
>   New(FReadBuf);
>   FReadBuf.Buffer := nil;
>   FReadBuf.NextRec := nil;
>   FWriteBuf := FReadBuf;
>
>
>procedure WriteBuf(Buf: Pointer; Len: Integer);
>begin
>   EnterCriticalSection(CSWrite);
>   if CanInput then
>   begin
>     New(NewBuf);
>     NewBuf.Buffer := nil;
>     NewBuf.NextRec := nil;
>     GetMem(FWriteBuf.Buffer,Len);
>     Move(Buf^,FWriteBuf.Buffer^,Len);
>     FWriteBuf.NextRec := NewBuf;
>     FWriteBuf.BufSize := Len;
>     FWriteBuf := NewBuf;
>     InterlockedExchangeAdd(@FBufferSize,Len);
>   End;
>   LeaveCriticalSection(CSWrite);
>end;
>
>Function ReadBuf(Buf: Pointer; Len: Integer): Integer;
>Var
>   TempBuf: pByte;
>begin
>   EnterCriticalSection(CSRead);
>   if not CanInput or (FBufferSize = 0) then Result := 0
>   else begin
>     if Len < FReadBuf.BufSize then
>     begin
>       Result := Len;
>       Move(FReadBuf.Buffer^,Buf^,Result);
>       TempBuf := FReadBuf.Buffer;
>       Inc(TempBuf,Result);
>       Move(TempBuf^,FReadBuf.Buffer^,FReadBuf.BufSize-Result);
>       Dec(FReadBuf.BufSize,Result);
>     end
>     else begin
>       Result := FReadBuf.BufSize;
>       Move(FReadBuf.Buffer^,Buf^,Result);
>       FreeMem(FReadBuf.Buffer);
>       FReadBuf.Buffer := nil;
>       NextBuf := FReadBuf.NextRec;
>       Dispose(FReadBuf);
>       FReadBuf := NextBuf;
>     end;
>     InterlockedExchangeAdd(@FBufferSize,-Result);
>   end;
>   LeaveCriticalSection(CSRead);
>end;
>
>procedure Seek(Pos: Integer);
>begin
>   CanInput := False;
>   EnterCriticalSection(CSWrite);
>   EnterCriticalSection(CSRead);
>   FAudio.Seek(Pos); // not shown
>   DeleteBuffers; // below
>   New(FReadBuf);
>   FReadBuf.Buffer := nil;
>   FReadBuf.NextRec := nil;
>   FWriteBuf := FReadBuf;
>   LeaveCriticalSection(CSRead);
>   LeaveCriticalSection(CSWrite);
>   CanInput := True;
>end;
>
>procedure DeleteBuffers;
>var
>   NextBuf: PBufRec;
>begin
>   while (FReadBuf <> nil) and (FReadBuf.Buffer <> nil) do
>   begin
>     NextBuf := FReadBuf.NextRec;
>     FreeMem(FReadBuf.Buffer);
>     Dispose(FReadBuf);
>     FReadBuf := NextBuf;
>   end;
>   if FReadBuf <> nil then
>   begin
>     Dispose(FReadBuf);
>     FReadBuf := nil;
>   end;
>   FBufferSize := 0;
>end;
>
>
>Thanks,
>Ross.
>
>_______________________________________________
>Delphi mailing list -> [email protected]
>http://www.elists.org/mailman/listinfo/delphi

_________________________________________________________________
与联机的朋友进行交流,请使用 Live Messenger; 
http://get.live.com/messenger/overview 


_______________________________________________
Delphi mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi

Reply via email to