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

