[Lazarus] Mutlithreaded Dll Callback crashes my Application
Alexander Grau
alex at grauonline.de
Wed Aug 25 17:48:01 CEST 2010
Sven Barth schrieb:
> Am 25.08.2010 17:02, schrieb Alexander Grau:
>>> Does it even work if you use threadvars? It should as the Heap uses
>>> threadvars, but I want to be sure. (and now I'm also curious to know
>>> why it works with 2.4.0 ^^)
>> I have modified the test - now it's using multiple external threads and
>> that works fine too until the moment I enable any 'writeln'. Using
>> threadvars or not doesn't make any difference. Using any writeln will
>> make it crash. If not using writeln, the external threads can call FPC
>> objects to increase some counters that are correctly displayed at the
>> end of the program for each thread.
>
> So the runtime must be tested more when using external threads... Does
> the writeln work when you use FPC threads?
Yes, using FPC threads it works - it crashes only when using external
threads.
Here's my latest and finest test code for both cases:
program project1;
{$APPTYPE CONSOLE}
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes,
{ you can add units after this }
windows;
{$R project1.res}
type
TSomeClass = class
public
procedure someMethod(idx: integer);
end;
const
USE_EXT_THREADS = true;
COUNT = 30;
var
i: integer;
threadid: DWORD;
ThreadHandles: array[1..COUNT] of THandle; //Rückgabewert von CreateThread
counters: array[1..COUNT] of integer;
someObj: TSomeClass;
FPCthreads: array[1..COUNT] of tthread;
type
TFPCThread = class(TThread)
protected
param: pointer;
ffinished: boolean;
procedure Execute; override;
public
constructor Create(aparam: pointer; CreateSuspended: boolean);
property finished: boolean read ffinished;
end;
constructor TFPCThread.Create(aparam: pointer; CreateSuspended: boolean);
begin
param:=aparam;
ffinished:=false;
FreeOnTerminate := false;
inherited create(CreateSuspended);
end;
procedure TFPCThread.execute;
var
t: tobject;
begin
t := TObject.Create;
try
Writeln(t.ClassName); // <--- here we get *NO* crash
finally
t.Free;
end;
someObj.someMethod(integer(param));
ffinished:=true;
end;
// ----------------------------------------------
procedure TSomeClass.someMethod(idx: integer);
begin
//writeln('TSomeClass.someMethod called');
inc(counters[idx]);
end;
procedure someFunc(param: pointer); cdecl;
var
t: tobject;
begin
//WriteLn('External is called - ThreadID=', GetCurrentThreadId);
//if assigned(param) then writeln('blub');
//writeln('param=', param);
t := TObject.Create;
try
Writeln(t.ClassName); // <--- here we get a crash
finally
t.Free;
end;
someObj.someMethod(integer(param));
end;
function ExternalThread(param: Pointer): LongInt; stdcall;
begin
someFunc(param);
Result:=0;
end;
begin
WriteLn('Main ThreadID=', GetCurrentThreadId);
someObj:=TSomeClass.create;
for i:=1 to COUNT do counters[i]:=0;
WriteLn('Creating external threads');
for i:=1 to COUNT do
begin
if USE_EXT_THREADS then
begin
ThreadHandles[i]:=CreateThread(nil, 0,
TFNThreadStartRoutine(@ExternalThread),
pointer(i), 0, ThreadID);
if ThreadHandles[i] = 0 then writeln('ERROR creating external
thread');
end else FPCThreads[i]:=TFPCThread.Create(pointer(i), false);
end;
readln;
WriteLn('Freeing external thread');
for i:=1 to COUNT do
begin
if USE_EXT_THREADS then
begin
if ThreadHandles[i]<>0 then CloseHandle(ThreadHandles[i]);
end else FPCThreads[i].free;
end;
someObj.free;
for i:=1 to COUNT do
writeln (counters[i]);
end.
More information about the Lazarus
mailing list