All jokes aside - trouble shooting threads is a pain period.

I have made life a lot easier for my development in this regard
implementing the following:

I made a TThread wrapper class that (germane to this discussion) has two
simple functions:

DBIN and DBOUT. They take the same parameters because I wasn't getting
fancy - just a means to and end. 

Here are the definitions:

type TJThread=class(TThread)

  public procedure DBIN(p_i8Code: int64; p_saFunction: ansistring;
p_saSourceFile: ansistring);

  public procedure DBOUT(p_i8Code: int64; p_saFunction: ansistring;
p_saSourcefile: ansistring);

  ..

end;


Note that I have compiler directives to exclude these everywhere in my
code that uses them... so I can flip one PRECOMPILER directive and lose
the code bloat...

The functions:


{$IFDEF DBINDBOUT}

//=============================================================================

procedure TJTHREAD.DBIN(
  p_i8Code: int64; 
  p_saFunction: ansistring; 
  p_saSourceFile: ansistring
);
//=============================================================================

var f: text;

    saFilename: ansistring;

begin

  safilename:=grJASCOnfig.saLogDir +
'TJTHREAD_'+inttostr(cardinal(self))+'.txt';

  try

    CSECTION_FILEREADMODEFLAG.Enter;

    FileMode:=READ_WRITE;

    {$I-}

    assign(f,safilename);

    if(fileexists(safilename)) then append(f) else rewrite(f);

    {$I+}

  finally

    CSECTION_FILEREADMODEFLAG.leave;

  end;

  // Don't really care if something changes the FILEMODE flag now
because my file is open in the mode I want
  // Of course I could add better IO handling here - like messing with
IORESULT... which is again
  // another FREEPASCAL global needing the same special attention. So,
because I don't want a huge bottle
  // neck accessing files - I limit the critical bit for the flag switch
and the file open.
  // I'm sure there is a better way - but this technique has solved many
headaches.

  {$I-}

  writeln(f,p_i8Code,'
',saDebugNest(p_saFunction,true,self.iNestLevel),' ',p_saSourcefile);

  close(f);

  {$I+}

end;

//=============================================================================

{$ENDIF}







{$IFDEF DBINDBOUT}

//=============================================================================

procedure TJTHREAD.DBOUT(
  p_i8Code: int64; 
  p_saFunction: ansistring; 
  p_saSourceFile: ansistring
);

//=============================================================================

var 

  dt: TDatetime;

  itempMSec: integer;

  //iRndRunNo: integer;

  f: text;

  saFilename: ansistring;

begin

  //riteln('DBOUT<--');

  safilename:=grJASCOnfig.saLogDir +
'TJTHREAD_'+inttostr(cardinal(self))+'.txt';

  try

    CSECTION_FILEREADMODEFLAG.Enter;

    FileMode:=READ_WRITE;

    {$I-}

    assign(f,safilename);

    if(fileexists(safilename)) then append(f) else rewrite(f);

    writeln(f,p_i8Code,'
',saDebugNest(p_saFunction,false,self.iNestLevel),' ',p_saSourcefile);

    close(f);

    {$I+}

  finally

    CSECTION_FILEREADMODEFLAG.leave;

  end;

end;

//=============================================================================

{$ENDIF}



The function saDebugNest is here for reference - makes the output file
meaningful because it visually indents nested calls and unindents when
DBOUT is called.

//=============================================================================

Function saDebugNest(
  p_saSectionName: AnsiString; 
  p_bBegin: Boolean; 
  var p_iNestLevel: integer
): AnsiString;

//=============================================================================

Const csBEGIN=' Begin';

Const csEND=  ' End  ';

Begin

  If p_bbegin Then

  Begin

    Result:=csBegin;

  End

  Else

  Begin

    p_iNestLevel-=1;

    If p_iNestLevel<0 Then

    Begin

      Result:=' NEST LEVEL < 0 ('+inttostr(p_iNestLevel)+')!! ';

    End;

    Result:=Result+csEnd;

  End;


  Result:=

    '|'+StringOfChar('.',p_iNestLevel)+p_saSectionName+ ' ' + 

    StringOfChar('-',128-length(p_saSectionName))+

    Result;
    

  If p_bBegin Then 

  begin

    p_iNestLevel+=1;

    Result:=' -   --->> '+Result; 

  end  

  Else

  begin

    Result:=' <<---   - '+Result;

  end;

End; 

//=============================================================================


Usage of this thing....


In inherited classes - these are easy to use, in other functions outside
the thread class - if I know 
I'm only using them with my threads - I pass a reference to the thread
just so I can hit the DBIN and DBOUT functions... 

example: SomeFunction( MyThread: TMyThreadReference); begin
MyThread.DBIN( etc) ; 

Ok - Typical implementation:

//=============================================================================

Procedure DoLogOut(p_Context:TCONTEXT);

//=============================================================================

Begin

{$IFDEF DEBUGLOGBEGINEND}

  DebugIn('DoLogOut',SourceFile);

{$ENDIF}

{$IFDEF
DBINDBOUT}p_Context.JThread.DBIN(201002030003,'dologout',SOURCEFILE);{$ENDIF}

  if not bJAS_RemoveSession(p_Context) then

  begin

    legacy_RenderHTMLErrorPage(p_Context,200610031958,'DoLogOut''s call
to Remove session failed. UserID:' + 
p_Context.rJUser.JUser_JUser_UID);   

  End;
  
{$IFDEF
DBINDBOUT}p_Context.JThread.DBOUT(201002030003,'dologout',SOURCEFILE);{$ENDIF}

{$IFDEF DEBUGLOGBEGINEND}
  DebugOut('DoLogOut',SourceFile);
{$ENDIF}

End;

//=============================================================================

There - Now - EACH THREAD get's it's own THREAD LOG file - with a record
(providing you implement this DBIN and DBOUT thing everywhere you can)
of where it choked. This ends up being almost as good as a realtime
debugger. In the kind of code I'm writing - I've yet to find a
FreePascal debugger that can do realtime debugging in a multithreaded
application - this is the next best thing. Before implementing this
solution - there was a lot of guess work - where now I'm zeroing in on
trouble spots which typically give me the clues I need to deal with the
real issue causing the choke.

--Jason




------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
synalist-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/synalist-public

Reply via email to