Hi,
What about the callback from the dll. I think this should at least be
mentioned as a possible solution.
Here is the code:
type
PVCMTThread = Pointer;
TVCMTThreadFunc = function (user_data:Pointer):Pointer;cdecl;
PCdeclThreadFunc = ^TCdeclThreadFunc;
TCdeclThreadFunc = record
Func: TVCMTThreadFunc; //cdecl function
Data: Pointer; //orig data
end;
{ C to pascal wrapper function.
BeginThread expects a 'register' function. Vortex supplies a 'cdecl'
function.}
function C2P_Translator(FuncData: pointer) : ptrint;
var
ThreadData: TCdeclThreadFunc;
begin
//Copy the supplied info
ThreadData := PCdeclThreadFunc(FuncData)^;
//Release memory allocated in fpc_vortex_thread_create()
dispose(PCdeclThreadFunc(FuncData));
//Finally we run the thread function
Result := ptrint(ThreadData.Func(ThreadData.Data));
end;
{ FPC specific thread create function to replace Vortex's thread create.
This is required because FPC doesn't work when C libraries create their own
threads}
//{$WARNINGS OFF} //For "cdecl'd functions have no high parameter"
function fpc_vcmt_thread_create(thread_def : PVCMTThread;
func : TVCMTThreadFunc;
user_data : Pointer):longint; cdecl;
var
ThreadData: PCdeclThreadFunc;
begin
//Pass thread information to C to Pascal wrapping function
New(ThreadData);
ThreadData^.Func := func;
ThreadData^.Data := user_data;
{$IFDEF WINDOWS}
//Start thread
TThreadID(thread_def^) := BeginThread(@C2P_Translator, ThreadData );
if TThreadID(thread_def) > 0 then
//Don't free memory here, it is done in the thread function
Result := 1
else
begin
//Free memory
dispose(ThreadData);
Result := 0;
end;
{$ENDIF}
//{$IFDEF UNIX}
// //Start thread
// BeginThread(@C2P_Translator, ThreadData, TThreadID(thread_def^) );
//
// if TThreadID(thread_def) > 0 then
// //Don't free memory here, it is done in the thread function
// Result := True
// else
// begin
// //Free memory
// dispose(ThreadData);
// Result := False;
// end;
//{$ENDIF}
end;
{$WARNINGS ON}
{ FPC specific thread destroy function to replace Vortex's thread destroy.
This is required because FPC doesn't work when C libraries create their own
threads}
function fpc_vcmt_thread_destroy(thread_def : PVCMTThread;
free_data : boolean):longint; cdecl;
var
Err: integer;
begin
{$IFDEF WINDOWS}
//Wait for thread
Err := WaitForThreadTerminate(TThreadID(thread_def), 0);
//Free resources
//if free_data then
// vcmtdll_Sys_Free(thread_def);
{$ENDIF}
//{$IFDEF UNIX}
// //Wait for thread
// Err := WaitForThreadTerminate(TThreadID(thread_def^), 0);
//
// //Free resources
// if 1 = free_data then
// tml_Sys_Free(thread_def);
//{$ENDIF}
if 0 = Err then
Result := 1
else
Result := 0;
end;
initialization
{$IFDEF FPC}
// Set pascal specific thread creators
vcmtdll__Thread_Set_OnCreate(@fpc_vcmt_thread_create);
vcmtdll__Thread_Set_OnDestroy(@fpc_vcmt_thread_destroy);
{$ENDIF}
The example with my dll can be downloaded for testing:
Server : support-ftp.wobe-team.com
User : lazarus
Pwd : test
It works with communication to the GUI baed on events (PostMessage). This
example crashed before.
Is there any hint that the FPC team will provide a fix for this in the near
future ?
Thanks
Maik
Alexander Grau schrieb:
Sven Barth schrieb:
Am 25.08.2010 23:07, schrieb José Mejuto:
On the other hand, if Unix needs one thread creation then it
should be
automagically done in the initialization section of cthreads, do
not ?
SB> This might indeed be a solution.
If windows have the same problem, threading system should be
initialized in... somewhere automagically as windows multithread is
always present.
This only solves one point (but is needed nevertheless).
As I've showed in the last message to Alexander yesterday evening you
need to initialize some things PER THREAD and I don't know whether
this can be automised. We might need to ask the FPC devs for help
regarding this. Perhaps the first time a threadvar in this new thread
is accessed might be a good possibilty, but I don't know (yet) how we
could track whether this is the first call, because threadvars are
not yet allocated (hen-egg-problem). I'll have to take a deeper look
into the threading system on Win32 :)
Regards,
Sven
I'm currently trying to summarize all aspects we discussed to add them
to the FreePascal Multithreading wiki page (see below) - did I
forget something that should be mentioned?
Thanks,
Alexander
External threads
To make Free Pascal's threading system to work properly, each newly
created FPC thread needs to be initialized (more exactly, the thread
local storage per thread needs to be initialized so threadvars and
heap are working). That is fully automatically done for you if you use
BeginThread (or indirectly by using the TThread class). However, if
you use threads that were created without BeginThread (i.e. external
threads), additional work (currently) might be required. External
threads also include those that were created in external C libraries
(.DLL/.so).
Things to consider when using external threads (might not be needed in
all or future compiler versions):
A) Initialize the FPC's threading system by creating a dummy thread:
{ initialise threading system }
with tc.create(false) do
begin
waitfor;
free;
end;
B) Make the runtime aware that your application uses multiple threads
in the first line of your application (.dpr):
IsMultithread:=true;
(This will make FPC routines to perform locks here and there.)
C) Do not use external threads at all - use FPC threads.
D) If for some reason this doesn't work for you, try this code in your
external thread function:
function ExternalThread(param: Pointer): LongInt; stdcall;
var
tm: TThreadManager;
begin
GetThreadManager(tm);
tm.AllocateThreadVars;
InitThread(100000000);
someFunc(param);
Result:=0;
end;
How to identify if your code is executed in an external thread context
1. Ask the OS for the ID of the current thread at your application's
start
Win32: WriteLn('Thread ID=', GetCurrentThreadID);
Darwin: WriteLn('Thread ID=', GetThreadID); Linux: Writeln('Thread
ID=', TThreadID(pthread_self) );
2. Ask again for the ID of the current thread inside the thread
function and compare this by the result of step 1.
--
_______________________________________________
Lazarus mailing list
[email protected]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
--
_______________________________________________
Lazarus mailing list
[email protected]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus