Recent

Author Topic: Using Synchronize in a DLL  (Read 11404 times)

calvarez

  • Newbie
  • Posts: 3
Using Synchronize in a DLL
« on: April 01, 2010, 04:55:31 pm »
I written an application that loads a DLL. The application also takes care of calling an exported function from the DLL to create and start a thread in the DLL. When the thread is running, it will be listening to packets that arrives at the servicing port. I encountered a problem if I wrapped my calls within the Execute(...) function with Synchronize(...). The application in fact, hang at the first wrapped Synchronize(...) call. However, if I take the wrapper out, the
application seems to be running fine. Previously, before I split my application into a DLL and a caller application, the use of Synchronize(...) posed no problems. But when I use
Synchronize(...) in a DLL, there are problems mentioned above. Thanks and kind regards.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12116
  • FPC developer.
Re: Using Synchronize in a DLL
« Reply #1 on: April 12, 2014, 11:21:09 am »
The trouble is that you have two sets of state related to synchronizing, since both the mainprogram and the DLL have a complete copy of the RTL state. (all variables)

To transparently divide a program in to multiple modules (mainprogram and DLLs) you need packages.

A workaround would be to somehow call the tthread.synchronize in the main program (e.g. by callback or so) so that all synchronization is done with only the mainprogram state.
« Last Edit: April 12, 2014, 06:59:54 pm by marcov »

eny

  • Hero Member
  • *****
  • Posts: 1646
Re: Using Synchronize in a DLL
« Reply #2 on: April 12, 2014, 12:27:47 pm »
To transparently divide a program in to multiple modules (mainprogram and DLLs) you need packages.
You mean this url  :)
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

CCRDude

  • Hero Member
  • *****
  • Posts: 614
Re: Using Synchronize in a DLL
« Reply #3 on: April 04, 2023, 12:17:45 pm »
Been there, more than once :) And am back to the topic this week, looking for other workarounds.

Background:
  • Code using threads in a git submodule often used
  • Changing the use to Lazarus packages instead
  • Previously, was using TDLLCompatibleThread that $IFDEF DLLThread used critical sections instead of Synchronize.
  • With packages, $IFDEF no longer seems to be an option
  • IsLibrary is said to be unreliable as well (system.inc seems to indicate this is true for packages).
  • Callback for Synchronize will not do because existing DLLs and other language hosts do not use it.
  • I also use this code in command line tools, some with TCustomApplication, some without.

In this situation, my ideas are:

  • Getting the current modules filename and checking extension for .dll (.so &c) might do, but fails on renamed file extensions,
  • is there a better FreePascal or, if not, operating system call to check if the currently running code is within a library?
  • Sounds like an ugly dependency, but Application.MainForm not being assigned might speak for the code to run from a DLL?
  • if (not Assigned(Application)) or (not (AppInitialized in Application.Flags)) could also indicate that thread synchronization is not available?
  • generally, looking for a way to detect if the synchronize mechanism is available would be better than just guessing by the file type of course

d2010

  • Full Member
  • ***
  • Posts: 122
Re: Using Synchronize in a DLL
« Reply #4 on: March 21, 2025, 03:19:13 pm »
I written an application that loads a DLL. The application also takes care of calling

stepA) I put here very ugly my-solution or C#/LPR/.DOF
stepB) I run reiterator not recursive the "Procedure vla_dcallnet100(exeW:word);"
stepC) But you need add
Using System.Windows.Forms,System.IO;
Using System.Drawing.Imaging;
Using System.Threading.Tasks;
stepD)You execute once "vla_dcallnet100"
stepE)The function vla_dcallnet100 call the 10000x  while (json>JsonNop) do ...sleep(30);end;
stepF)Main program docecolo.pas or docecolo.exe , 
 link to external  cook3260.DLL
The cook3260.dll link to chaiajnax.ROM (as idem docecolo.exe->cook3260.dll)

I arrange three programs from top to bottom.
Level-Level= docecolor.exe  link to cook.dll-once and link-one-fix
Mid-Leve=cook3260.dpr  link dynamically with cecolord.rom or codostee.rom
or any .rom. Here you can replace cecolord.rom with multiples file *.rom
Low-level=cecolord.rom
             chiajanx.rom
             codostree.rom
calfelix.rom,certwget.rom, cexplore.rom, cfontdwg.rom, cimapitb.rom
cip03dcl.rom, cisavbak.rom, ckeystat.rom, clc2stex.rom, clibjpeg.rom
clistene.rom, clistsvc.rom, cnotepad.rom, coarrint.rom, coasiapp.rom
cobmpaxo.rom, cobmpcur.rom, cobmpers.rom, cobmplsp.rom, cobroken.rom
coc2sbat.rom, coc2sclj.rom, coc2sgmp.rom, coc2slsp.rom, cocabine.rom,
cocmdhtm.rom, cocppdie.rom, codiecpp.rom, codoclsp.rom, codocrtf.rom
codotdoc.rom, codotrtl.rom, codotrtm.rom, codsound.rom, codstree.rom
cofcache.rom, cogifhat.rom, cogifmsg.rom, coicomtx.rom, coicoxls.rom
coimgvue.rom, coinject.rom, colinlsp.rom, colspsds.rom, comapitb.rom
comcatcc.rom, comicttf.rom, comnslsp.rom,compittf.rom,conint64.rom
LowLow-level=

'Blade2024RunnerEndless06Streets
 :'( %) 8) 8)
Question1?
C:Q1 how comunicate any lib.rom with main-executable docecolo.exe?
C:Q2 Please any help, Do with more gather informantion/s? Work good or not?
By About Linux? How does-it?
the

Code: [Select]
Function docecolo_loaddoc(driverexp:char):integer;external 'cook3260.dll';
Procedure docecolo_freedoc(indx:word);external 'cook3260.dll';
Function docecolo_callbak(c:integer):integer; external 'cook3260.dll';
Function docecolo_calldoc(indexPavel,cmx:word):integer;external 'cook3260.dll';
The main-handler
Function docecolo_calldoc(indexPavel,cmx:word):integer;external 'cook3260.dll';

My main trick are these lines.
Code: [Select]
Procedure vla_dcallnet100(exeW:word);
     Try
  Parallel.Invoke (
    procedure -> begin
                while (json>JsonNop) do
                   {
                             if (json=JsonRun) then {
                                            Json=JsonWait;//YOu must be sure do not overfull of call.
                                            docecolo_calldoc(Direct2D1.x,Direct2D1.y);
                                            Json=JsonNop
                                             } else
                                 Sleep(30);
                           }
           }; //end/while while  . 10000x of checking Json the variabiles ONLY
Eu multumesc tie ArsenieBoca.
Code: [Select]
Procedure vla_dcallnet100(exeW:word);
Var ercad:integer;
{ ercad:=RTGOOD;
     Try
  Parallel.Invoke (
    procedure -> begin
                while (json>JsonNop) do
                    {
                             if (json=JsonRun) then {
                                            Json=JsonWait;
                                            docecolo_calldoc(Direct2D1.x,Direct2D1.y);
                                            Json=JsonNop
                                             } else
                                 Sleep(30);
                           }
           }
    procedure -> begin
            Blade2020Runner();
         }
            );         
Except ercad:=RTCAN;
  }
stepG) inside Cook3260.dll
[code] the cook3260 .dll is only autoloader.

Function docecolo_loaddoc(driverexp:char):integer;stdcall;
Begin
     Result:=RTCAN;
     ddrawcompat.err :=RTCAN;
     ddrawcompat.drv :='A';
     ddrawcompat.dll:=SafeLoadLibrary(ktoolsize_cecolor32dll,get_semantic);
  if (ddrawcompat.dll<255) then
          Begin ktoolsize_cecolor32dll[0]:=driverexp;
                ddrawcompat.dll:=SafeLoadLibrary(ktoolsize_cecolor32dll,get_semantic);
                if (ddrawcompat.dll<255) then
                  Begin ktoolsize_cecolor32dll[0]:=php_comcatc;
                          ddrawcompat.dll:=SafeLoadLibrary(ktoolsize_cecolor32dll,get_semantic);
                  End;
                if (ddrawcompat.dll<255) then  exit;
          End;
     @ddrawcompat.fnc:=vla_get_ProcAddress(ddrawcompat.dll,'Blade2024RunnerEndless06Streets'#0#0#0);
     if (@ddrawcompat.fnc<>nil) then
                 Begin ddrawcompat.err:=RTGOOD;
                       ddrawcompat.drv:=ktoolsize_cecolor32dll[0];                 
                       Result:=RTNORM;
                 End
                   else result:=RTFAIL;
End;
stepH)Here code of cook3260.dll
Code: [Select]
Var ddrawcompat.fnc:function
Function docecolo_calldoc(indexPavel:integer):integer; stdcall;
Begin  Result:=100;
   Try ddrawcompat.fnc(ddrawcompat.drv,indexPavel);
       Except result:=RTCAN;
       End;
       if (result>0) then result:=RTGOOD;
End;
stepI) the cook3260 is main-autoloader of .Rom". You rename your external
ddrawcompat.dll:=SafeLoadLibrary(NAME-OF-ROM-FROM-ORG.DLL,get_semantic);

.dll as .rom.
stepj)
Code: [Select]
Function docecolo_loaddoc(driverexp:char):integer;stdcall;
Begin
     Result:=RTCAN;
     ddrawcompat.err :=RTCAN;
     ddrawcompat.drv :='A';
     ddrawcompat.dll:=SafeLoadLibrary(ktoolsize_cecolor32dll,get_semantic);
  if (ddrawcompat.dll<255) then
          Begin ktoolsize_cecolor32dll[0]:=driverexp;
                ddrawcompat.dll:=SafeLoadLibrary(ktoolsize_cecolor32dll,get_semantic);
                if (ddrawcompat.dll<255) then
                  Begin ktoolsize_cecolor32dll[0]:=php_comcatc;
                          ddrawcompat.dll:=SafeLoadLibrary(ktoolsize_cecolor32dll,get_semantic);
                  End;
                if (ddrawcompat.dll<255) then  exit;
          End;
     @ddrawcompat.fnc:=vla_get_ProcAddress(ddrawcompat.dll,'Blade2024RunnerEndless06Streets'#0#0#0);
     if (@ddrawcompat.fnc<>nil) then
                 Begin ddrawcompat.err:=RTGOOD;
                       ddrawcompat.drv:=ktoolsize_cecolor32dll[0];                 
                       Result:=RTNORM;
                 End
                   else result:=RTFAIL;
End;
Eu multumesc tie ArsenieBoca.
« Last Edit: March 21, 2025, 03:52:26 pm by d2010 »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1485
    • Lebeau Software
Re: Using Synchronize in a DLL
« Reply #5 on: March 21, 2025, 03:47:58 pm »
The trouble is that you have two sets of state related to synchronizing, since both the mainprogram and the DLL have a complete copy of the RTL state. (all variables)

Yes, and because of that, the DLL should export another function that calls the CheckSynchronize() function of its copy of the RTL. And then the main app should call that export periodically, such as inside its message loop, or in a timer, or an OnIdle event handler, etc.
« Last Edit: March 21, 2025, 11:57:57 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

MarkMLl

  • Hero Member
  • *****
  • Posts: 8334
Re: Using Synchronize in a DLL
« Reply #6 on: March 21, 2025, 09:46:05 pm »
Well, I really don't see why we're resuscitating a thread that died ten years ago, but here's my 2d'orth which is broadly in agreement with Marco (happens on occasion :-)

The main program and each shared library (.dll or .so, henceforth "library") will have its own copy of the RTL and possibly much more. A program using multiple libraries (as plugins etc.) might thus have many copies of the RTL, FCL, LCL and so on.

The main program and libraries should use cmem. If HeapTrace is needed, this should be imported by the main unit after cmem, followed by threads support.

Any GUI element (object, component etc.) defined as part of a library must be copied into the main program before it can be used directly (for example, a menu structure).

It is probably unwise to expect a Synchronize() across the boundary between a library and main program to be safe.

The main program can call library entry points by name.

A library can call main program entry points by name.

I can't offer definitive proof of this, but my opinion is that it would be best to have the main program start a thread to e.g. handle background comms, which calls a library routine for filtering, which then enqueues data guarded by a critical section.

The serial.pp unit in the RTL was specifically reworked to capture timestamped data using a background thread. The joke is that I found it necessary to write a serial comms analyser to work out how two high-end HP comms analysers were talking to each other :-)

There's relevant demo code in https://github.com/MarkMLl/dynamod and https://github.com/MarkMLl/dsocat. Much of the underlying technology dates back to around 2012 when I wrote a filter for MIDI data which allowed a backend library to be reloaded without (crashing or) interrupting data flow.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1485
    • Lebeau Software
Re: Using Synchronize in a DLL
« Reply #7 on: March 21, 2025, 11:59:12 pm »
Well, I really don't see why we're resuscitating a thread that died ten years ago

I didn't see the timestamps :o
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018