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