Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2012-06

Library, Threads and Gui

15 messages · 7 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

SteveG

I understand that the gui system is non-reentrant, and therefore should not be accessed by any thread but the main one.

I am using cmem as my memory manager for both my app and library (if thats relevant), and it would appear that the entrant thread of the library is the same as the main app ?

So.... is it safe to read / write to gui components (I have the control addresses) from within the library (no new threads created) without problems ?

To summarise - can I rd/wr to form controls from within a cmem controlled library using its main thread ?

Thanks - SteveG

Reply by email

Mattias Gaertner
to SteveG
I understand that the gui system is non-reentrant, and therefore should not be accessed by any thread but the main one.

yes

I am using cmem as my memory manager for both my app and library (if thats relevant),

yes it is relevant.
If you have two memory managers you can not exchange strings and classes.

and it would appear that the entrant thread of the library is the same as the main app ?

Yes.

What OS?

So.... is it safe to read / write to gui components (I have the control addresses) from within the library (no new threads created) without problems ?

The "is" operator requires that the library uses the VMTs of the main application.

To summarise - can I rd/wr to form controls from within a cmem controlled library using its main thread ?

Yes, to some degree.

Mattias

Reply by email

Michael Schnell
to Mattias Gaertner: On Tue, 05 Jun 2012 10:18:04 +0930 yes yes it is relevant. If you have two memory…
Mattias Gaertner wrote
yes it is relevant. If you have two memory managers you can not exchange strings and classes.

Is cmem "the way to go" to unify the memory managers of a dynamic library and the calling application ? (There seem more advanced free alternatives written for Delphi, that might be usable with FPC.)

Will just "using" cmem both in the main program and in the library automatically unify the memory managers ?

http://wiki.freepascal.org/Multithreaded_Application_Tutorial states:

cmem, // the c memory manager is on some systems much faster for multi-threading

and

You can not use the -gh switch with the/cmem/ unit. The -gh switch uses the heaptrc unit, which extends the heap manager. Therefore the*heaptrc* unit must be used*after* the*cmem* unit.

Should the FPC memory manager not be more optimized for FPC code then cmem ?

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20120605/adfb9663/attachment.html>

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 9 lines
On 06/05/2012 08:29 AM, Mattias Gaertner wrote: > yes it is relevant. If you have two memory managers you can not > exchange strings and classes. Is cmem "the way to go" to unify the memory managers of a dynamic library and the calling application ? (There seem more advanced free alternatives written for Delphi, that might be usable with FPC.) Will just "using" cmem both in the main program and in the library automatically unify the memory managers ?

Under Linux: yes. I guess BSD, OS X
too. The Delphi alternatives work only on MS Windows.

Show quoted text 12 lines
http://wiki.freepascal.org/Multithreaded_Application_Tutorial states: cmem, // the c memory manager is on some systems much faster for multi-threading and You can not use the -gh switch with the/cmem/ unit. The -gh switch uses the heaptrc unit, which extends the heap manager. Therefore the*heaptrc* unit must be used*after* the*cmem* unit. Should the FPC memory manager not be more optimized for FPC code then cmem ?

Yes, it normally is.
It was slower with multithreading on some systems. The FPC heap manager was improved for OS X. Do some tests to find out which one is better for your application.

Mattias

Reply by email

SteveG
to Mattias Gaertner: On Tue, 05 Jun 2012 10:18:04 +0930 yes yes it is relevant. If you have two memory…

Thanks guys - I have been using this approach in my Linux libs for awhile now, and appears to work ok.

Just having intermittant gtk errors within my library and trying to determine if the Lib -> Gui area may be my problem (no extra threads in use)

So probably need to look elsewhere at what I'm doing wrong

Mattias Gaertner wrote 39 lines
On Tue, 05 Jun 2012 10:18:04 +0930 SteveG wrote: > I understand that the gui system is non-reentrant, and therefore should > not be accessed by any thread but the main one. yes > I am using cmem as my memory manager for both my app and library (if > thats relevant), yes it is relevant. If you have two memory managers you can not exchange strings and classes. > and it would appear that the entrant thread of the > library is the same as the main app ? Yes. What OS? > So.... is it safe to read / write to gui components (I have the control > addresses) from within the library (no new threads created) without > problems ? The "is" operator requires that the library uses the VMTs of the main application. > To summarise - can I rd/wr to form controls from within a cmem > controlled library using its main thread ? Yes, to some degree. Mattias -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Mark Morgan Lloyd
to Mattias Gaertner: On Tue, 05 Jun 2012 10:18:04 +0930 yes yes it is relevant. If you have two memory…
Mattias Gaertner wrote 36 lines
On Tue, 05 Jun 2012 10:18:04 +0930 SteveG wrote: > I understand that the gui system is non-reentrant, and therefore should > not be accessed by any thread but the main one. yes > I am using cmem as my memory manager for both my app and library (if > thats relevant), yes it is relevant. If you have two memory managers you can not exchange strings and classes. > and it would appear that the entrant thread of the > library is the same as the main app ? Yes. What OS? > So.... is it safe to read / write to gui components (I have the control > addresses) from within the library (no new threads created) without > problems ? The "is" operator requires that the library uses the VMTs of the main application. > To summarise - can I rd/wr to form controls from within a cmem > controlled library using its main thread ? Yes, to some degree.

Please can I tack a related question onto this. If I have analogous forms in a main program and shared library (.dll or .so), where the menu structure in the main form is built up from what's in the library, can the main program's menu call OnClick() events in the library safely?

What I'm hoping to do is use the library's form(s) purely for design purposes, i.e. they're never displayed but instead their menu structure is copied to the main program. Non-graphical backend functionality would be in the library, and I've obviously got the choice of attempting to control this using OnClick() etc. or by passing commands in strings to be parsed.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Mattias Gaertner
to Mark Morgan Lloyd

Mark Morgan Lloyd hat am 5. Juni 2012 um 11:57
geschrieben:

Show quoted text 12 lines
[...] Please can I tack a related question onto this. If I have analogous forms in a main program and shared library (.dll or .so), where the menu structure in the main form is built up from what's in the library, can the main program's menu call OnClick() events in the library safely? What I'm hoping to do is use the library's form(s) purely for design purposes, i.e. they're never displayed but instead their menu structure is copied to the main program. Non-graphical backend functionality would be in the library, and I've obviously got the choice of attempting to control this using OnClick() etc. or by passing commands in strings to be parsed.

An event is just a method pointer (instance+address). So you can connect even a C library if the method signature fits. Of course not via the designer, but by code. So, yes you can call pascal functions in libs.

But you have to be careful with all shared things that uses compiler magic like classes, strings, interfaces, global variables.

See

http://wiki.freepascal.org/packages

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20120605/dccb063e/attachment.html>

Reply by email

Michael Schnell
to Mattias Gaertner: On Tue, 05 Jun 2012 09:33:53 +0200 Under Linux: yes. I guess BSD, OS X too. The Delphi…
Mattias Gaertner wrote 7 lines
On Tue, 05 Jun 2012 09:33:53 +0200 Michael Schnell wrote: > Will just "using" cmem both in the main program and in the library > automatically unify the memory managers ? Under Linux: yes. I guess BSD, OS X too.

If cmem can do this so easily, would it not be a good idea to upgrade the FP memory manager so that it can (optionally) do this, as well, so that dynamically linked projects work appropriately "out of the box" ?

-Michael

Reply by email

Michael Schnell
to Mark Morgan Lloyd: Please can I tack a related question onto this. If I have analogous forms in a main…
Mark Morgan Lloyd wrote 9 lines
What I'm hoping to do is use the library's form(s) purely for design purposes, i.e. they're never displayed but instead their menu structure is copied to the main program. Non-graphical backend functionality would be in the library, and I've obviously got the choice of attempting to control this using OnClick() etc. or by passing commands in strings to be parsed.

AFAIK, (I did not use menus on that behalf, but I think it should work with Panels, buttons, etc), setting the parent property should "move" a control to new form. Maybe Owner should be modified accordingly to prevent that the child is deleted before the new parent.

-Michael

Reply by email

Mark Morgan Lloyd
to Michael Schnell
Michael Schnell wrote 13 lines
On 06/05/2012 11:57 AM, Mark Morgan Lloyd wrote: > > > What I'm hoping to do is use the library's form(s) purely for design > purposes, i.e. they're never displayed but instead their menu > structure is copied to the main program. Non-graphical backend > functionality would be in the library, and I've obviously got the > choice of attempting to control this using OnClick() etc. or by > passing commands in strings to be parsed. > AFAIK, (I did not use menus on that behalf, but I think it should work with Panels, buttons, etc), setting the parent property should "move" a control to new form.

Thanks and noted, although I was intending (subject to comment from people who know what they're doing :-) to do a property-by-property copy from the non-displayed TMenuItems in the library to the displayed ones in the main program.

Maybe Owner should be modified accordingly to prevent that the child is deleted before the new parent.

Which I suspect would be an issue where a shared library was intentionally unloaded, although in practice it would be expedient to make sure that anything that was likely to be recreated was removed first.

Also noted Mattias's comment that I should be able to call an event directly, which obviously makes life much easier.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Kostas Michalopoulos
to Mattias Gaertner: On Tue, 05 Jun 2012 10:18:04 +0930 yes yes it is relevant. If you have two memory…
Mattias Gaertner wrote
The "is" operator requires that the library uses the VMTs of the main application.

What does that imply exactly? I made a quick app to test the possibility of using DLLs for plugins. Both the app and the DLL uses a unit that contains the following class:

TGBrush = class(TComponent)
protected
function GetBrushEditor: TWinControl; virtual; abstract;
function GetName: string; virtual; abstract;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Push(ACanvas: TCanvas; X, Y: Integer); virtual;
procedure Release(ACanvas: TCanvas; X, Y: Integer); virtual;
procedure Draw(ACanvas: TCanvas; X1, Y1, X2, Y2: Integer); virtual;
abstract;
property BrushEditor: TWinControl read GetBrushEditor;
property Name: string read GetName;
end;

And also another class that contains a list with TGBrush objects like the above. These objects access both a TCanvas from the main application and will return a TWinControl descendant (most likely, but not necessarily, a TFrame designed in Lazarus) created by the DLL that will be embedded in a TPanel in the main application.

When adding a new object i use the "is" operator to see if it is a descendant of TGBrush and this always fails. My current setup is to pass the memory manager of the application and the shared brushes object to the library:

var
MemMgr: TMemoryManager
GetMemoryManager(MemMgr);
RegProc:=TGBrushDLLRegisterProc(GetProcedureAddress(Lib,
'BrushDLLRegister'));
if Assigned(RegProc) then RegProc(MemMgr, GBrushes);

And from the DLL side use the memory manager as the first thing and call Application.Initialize:

procedure BrushDLLRegister(const AppMemoryManager: TMemoryManager;
GBrushes: TGBrushes);
begin
SetMemoryManager(AppMemoryManager);
// The call to Application.Initialize is made because i read
// in the forums that it is needed from libraries to "sync"
// the two instances together
Application.Initialize;
// here the TGBrush constructor checks if its owner is a
// TGBrushes descendant using the "is" operator and fails
TSprayGBrush.Create(GBrushes);
end;

Why exactly the "is" operator fails and how can it be fixed? And how will all the above work under Windows, Linux and Mac OS X?

If needed i can put somewhere the full program i used for testing, but i think the above shows what i'm trying to do.

Kostas "Bad Sector" Michalopoulos

Reply by email

Mark Morgan Lloyd
to Michael Schnell: If cmem can do this so easily, would it not be a good idea to upgrade the FP memory…
Michael Schnell wrote 11 lines
On 06/05/2012 09:47 AM, Mattias Gaertner wrote: > On Tue, 05 Jun 2012 09:33:53 +0200 > Michael Schnell wrote: > >> Will just "using" cmem both in the main program and in the library >> automatically unify the memory managers ? > Under Linux: yes. I guess BSD, OS X > too. If cmem can do this so easily, would it not be a good idea to upgrade the FP memory manager so that it can (optionally) do this, as well, so that dynamically linked projects work appropriately "out of the box" ?

Is it possible to look at a pointer or object, and decide unambiguously whether it makes sense in the context of the current memory manager, or is a rogue that's been passed from elsewhere and should be treated with caution?

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Sven Barth
to Kostas Michalopoulos: What does that imply exactly? I made a quick app to test the possibility of using DLLs…
Kostas Michalopoulos wrote 6 lines
On 5/6/2012 9:29 ??, Mattias Gaertner wrote: > The "is" operator requires that the library uses the VMTs of the main > application. What does that imply exactly? I made a quick app to test the possibility of using DLLs for plugins. Both the app and the DLL uses a unit that contains the following class:

[...]

Why exactly the "is" operator fails and how can it be fixed? And how will all the above work under Windows, Linux and Mac OS X?

If you use a unit in a library and a program the VMTs (Virtual Method Table) of the classes in that unit are available in both the program and the library as well. An object instance (and class type as well) is basically identified by its VMT pointer. Now if the library uses an "is" on a object instance passed from the program the VMT pointer the library expects and what the code behind "is" discovers will be different and thus the two objects will be different even if they come from the same source unit.

The only solution for this will be dynamically loadable packages as described here: http://wiki.freepascal.org/packages

No one is currently working on an implementation of this though and it also isn't a high priority item so it will take quite some time until this is implemented (if ever).

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Kostas Michalopoulos: What does that imply exactly? I made a quick app to test the possibility of using DLLs…
When adding a new object i use the "is" operator to see if it is a descendant of TGBrush and this always fails.

This is because the DLL uses an different tree of object classes. It includes System, Classes etc. units, as duplicates of the main program units (see the linker map).

In theory you need another DLL/so which contains all these common units (RTL+basic LCL), and which is used by all modules of the project. In practice this may not work, though :-(

DoDi

Reply by email