[Lazarus] What to replace Application.Processmessages with?

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

[Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
I have been working some time to convert a rather big Delphi2007
Windows service application to a regular Linux program possible to run
as a Linux systemd service.
In Linux I was told that the application needs to be a regular program
to run in a non-logged on setting on a Linux server (without desktop).

So I have come a long way now and it feels like i am in the final
stretch.
All of the TCP/IP socket communications to a client config app and
handling of serial ports and digital I/O has been solved.
The program runs OK at its core as a non-gui app and I can use the
existing client application on Windows to talk to it and configure the
system etc.

But now when I approach the actual core of the service, the ability to
run a longish task on external hardware while still being able to
handle incoming client requests etc I have found a possible problem...

The original server on Windows was built as a TService application and
had the GUI support maybe via a Delphi data module or otherwise so the
Application object is available.
I had to change this to a simple program instead and so I lost the
Application object.

In a lot of places in the task execution code there are
Application.Processmessages in wait loops and these I had to switch
off via a conditional named GUI_MODE and instead I have a sleep(T)
call there. Example:

while FContactResTestRunning and not FCancelOp do
  begin
    {$IFDEF GUI_MODE}
      Application.ProcessMessages;
    {$ENDIF}
    Sleep(50);
  end;

Here the booleans FContactResTestRunning and FCancelOp are supposed to
be set in the main application on reception of certain events.

NOTICE:
The class file where all of this is coded is also used in a GUI
application on Windows where the user communicates with the
instrumentation manually from the app. In that setting Application is
available and all works well.

The service application itself (from 2004) is based on timers to
perform things like execution of the measurement task itself in order
to isolate that from the main application. That is why there is
Application.Processmessages inside the wait loops so that things like
reception of RS232 messages from the equipment can be handled and
analyzed and flags be set which are waited for in the timer...

The TTimer objects have been replaced by TFpTimer objects in the
ported code and this seems to work fine, whereas TTimer does not.

I know that the system should have been designed using threads
instead, but that is not there and it is probably a too difficult
project to try and replace the current structure with threads.

Now I wonder if I could put something else into the loops so that the
main object of Application.Processmessages will be handled, namely to
let event functions run as needed.
Can I for example use CheckSynchronize in these loops?

I.e. Application.Processmessages ==> CheckSynchronize?

Or is there any other way?

--
Bo Berglund
Developer in Sweden

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list


On Tue, 13 Oct 2020, Bo Berglund via lazarus wrote:

> Now I wonder if I could put something else into the loops so that the
> main object of Application.Processmessages will be handled, namely to
> let event functions run as needed.
> Can I for example use CheckSynchronize in these loops?
>
> I.e. Application.Processmessages ==> CheckSynchronize?

Based on your description, that is all you need to do.

But I would create a routine

Procedure HandleMainLoop;

begin
{$IFDEF NOGUI}
   CheckSynchronize;
{$ELSE}
   Application.ProcessMessages;
{$ENDIF}
end;

And call that both in GUI and NOGUI.

Michael.
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On 13/10/2020 9:15 am, Bo Berglund via lazarus wrote:
> The TTimer objects have been replaced by TFpTimer objects in the
> ported code and this seems to work fine, whereas TTimer does not.

That is the key part, using TFPTimer is thread based, so calling
CheckSynchronized() would be the solution to keep things ticking
over.

Michael made a good suggestion, by wrapping that code into a method,
so it is easier to maintain, and that wrapper method is more
descriptive (ie: self documenting your code).


In the long term I would highly suggest converting that code / tasks
to multiple theads. From what you described, they sound like good
candidates for a thread based system.

Regards,
  Graeme

--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Mon, 26 Oct 2020 13:00:26 +0100 (CET)
Michael Van Canneyt via lazarus <[hidden email]> wrote:

>[...]
> Procedure HandleMainLoop;
>
> begin
> {$IFDEF NOGUI}
>    CheckSynchronize;
> {$ELSE}
>    Application.ProcessMessages;
> {$ENDIF}
> end;
>
> And call that both in GUI and NOGUI.

Application.ProcessMessages calls CheckSynchronize in NoGUI.

Mattias
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list


On Tue, 27 Oct 2020, Mattias Gaertner via lazarus wrote:

> On Mon, 26 Oct 2020 13:00:26 +0100 (CET)
> Michael Van Canneyt via lazarus <[hidden email]> wrote:
>
>> [...]
>> Procedure HandleMainLoop;
>>
>> begin
>> {$IFDEF NOGUI}
>>    CheckSynchronize;
>> {$ELSE}
>>    Application.ProcessMessages;
>> {$ENDIF}
>> end;
>>
>> And call that both in GUI and NOGUI.
>
> Application.ProcessMessages calls CheckSynchronize in NoGUI.

NOGUI does not mean 'use nogui LCL'

He does not use the LCL in that mode, so Application is not available.

Michael.
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Mon, 26 Oct 2020 13:00:26 +0100 (CET), Michael Van Canneyt via
lazarus <[hidden email]> wrote:

>
>
>On Tue, 13 Oct 2020, Bo Berglund via lazarus wrote:
>
>> Now I wonder if I could put something else into the loops so that the
>> main object of Application.Processmessages will be handled, namely to
>> let event functions run as needed.
>> Can I for example use CheckSynchronize in these loops?
>>
>> I.e. Application.Processmessages ==> CheckSynchronize?
>
>Based on your description, that is all you need to do.
>
>But I would create a routine
>
>Procedure HandleMainLoop;
>
>begin
>{$IFDEF NOGUI}
>   CheckSynchronize;
>{$ELSE}
>   Application.ProcessMessages;
>{$ENDIF}
>end;
>
>And call that both in GUI and NOGUI.
>

Is NOGUI defined also when *not* using the nogui widgetset? I.e. in a
simple program?


--
Bo Berglund
Developer in Sweden

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list


On Wed, 28 Oct 2020, Bo Berglund via lazarus wrote:

> On Mon, 26 Oct 2020 13:00:26 +0100 (CET), Michael Van Canneyt via
> lazarus <[hidden email]> wrote:
>
>>
>>
>> On Tue, 13 Oct 2020, Bo Berglund via lazarus wrote:
>>
>>> Now I wonder if I could put something else into the loops so that the
>>> main object of Application.Processmessages will be handled, namely to
>>> let event functions run as needed.
>>> Can I for example use CheckSynchronize in these loops?
>>>
>>> I.e. Application.Processmessages ==> CheckSynchronize?
>>
>> Based on your description, that is all you need to do.
>>
>> But I would create a routine
>>
>> Procedure HandleMainLoop;
>>
>> begin
>> {$IFDEF NOGUI}
>>   CheckSynchronize;
>> {$ELSE}
>>   Application.ProcessMessages;
>> {$ENDIF}
>> end;
>>
>> And call that both in GUI and NOGUI.
>>
>
> Is NOGUI defined also when *not* using the nogui widgetset? I.e. in a
> simple program?

As far as I know you must define this yourself.

Michael.
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Tue, 27 Oct 2020 21:25:55 +0000, Graeme Geldenhuys via lazarus
<[hidden email]> wrote:

>In the long term I would highly suggest converting that code / tasks
>to multiple theads. From what you described, they sound like good
>candidates for a thread based system.

Yes, I agree, but...

The code is pretty big and very hard to follow these many years since
it was created...

I wanted to get it running first with as small changes as possible and
I thought I had that nailed until I started an actual execution on the
hardware and found that I could set it up properly and start it but
then nothing more is happening.
So there are probably other places where events are important, I
guess, and I have to track down these as well...

I am now thinking of creating some kind of general purpose thread
object in order to track progress on the hardware but without doing
much else, because the timer event was there in order to detatch the
task execution from the body of the program so that it could run other
things meanwhile. Some tasks take hours to execute...
But initializing a run takes only some seconds so that could remain in
mainline code if only the progress monitoring is handled in the
thread.

Of course I have to communicate the state of affairs to mainline from
the thread...
Could be done by changing boolean variable states (I assume a boolean
which is just a single bit should be inherently thread-safe).

Or else having an event in the thread to message into the mainline
code using Synchronize().


--
Bo Berglund
Developer in Sweden

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Mon, 26 Oct 2020 13:00:26 +0100 (CET), Michael Van Canneyt via
lazarus <[hidden email]> wrote:

>But I would create a routine
>
>Procedure HandleMainLoop;
>
>begin
>{$IFDEF NOGUI}
>   CheckSynchronize;
>{$ELSE}
>   Application.ProcessMessages;
>{$ENDIF}
>end;
>
>And call that both in GUI and NOGUI.

I decided to check how Lazaus implements Application.Processmessages.
It seems to start in the Forms unit and then redirects into
application.inc where I found this (on Windows):

{------------------------------------------------------------------------------
  TApplication ProcesssMessages  "Enter the messageloop and process
until empty"
------------------------------------------------------------------------------}
procedure TApplication.ProcessMessages;
begin
  if Self=nil then begin
    // when the programmer did a mistake, avoid getting strange errors
    raise Exception.Create('Application=nil');
  end;
  WidgetSet.AppProcessMessages;
  ProcessAsyncCallQueue;
end;

If I try to find how WidgetSet.AppProcessMessages; looks like then I
get to a dead end:

procedure AppProcessMessages; virtual; abstract; (no implementation)

And ProcessAsyncCallQueue seems to be doing the job with pretty
intricate code inside a CriticalSection shield.

QUESTION:
Is there a way in code to check if Forms is used?
So it can be used instead of {$IFDEF NOGUI}


--
Bo Berglund
Developer in Sweden

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list


On Sun, 1 Nov 2020, Bo Berglund via lazarus wrote:

> procedure AppProcessMessages; virtual; abstract; (no implementation)
>
> And ProcessAsyncCallQueue seems to be doing the job with pretty
> intricate code inside a CriticalSection shield.
>
> QUESTION:
> Is there a way in code to check if Forms is used?
> So it can be used instead of {$IFDEF NOGUI}

normally

{$IF DECLARED(Forms)}
or
{$IF DECLARED(TForm)}

should do the trick for you.

Michael.
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
On Sun, 1 Nov 2020 10:20:11 +0100 (CET), Michael Van Canneyt via
lazarus <[hidden email]> wrote:

>> QUESTION:
>> Is there a way in code to check if Forms is used?
>> So it can be used instead of {$IFDEF NOGUI}
>
>normally
>
>{$IF DECLARED(Forms)}
>or
>{$IF DECLARED(TForm)}
>
>should do the trick for you.

A quick test:
It seems like there is a problem with this...
I added this to the end of a random function:

  {$IF DECLARED(TForm)}
    Application.ProcessMessages;
  {$ENDIF}

Even though the project does not use Forms (Search/Find in Files in
all project files does not find it) the code within the block is
marked enabled and a quick compile succeeds.

No file in the project declares Forms as a used unit.
Same thing happens if I check for Forms in the code above...

If I try to use the right-click/FindDeclarationOf on Processmessages
pops up an error:
class_SSRemoteServer.pas(530,5) Error: identifier not found:
Application

However, the app builds...
So maybe this is a problem with the Lazarus code editor not being able
to parse the {$IF DECLARED(TForm/Forms)} item?

To really check this I need to create a test app and run it in the
debugger, I guess..
In a command line program it should not generate code, right?


--
Bo Berglund
Developer in Sweden

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Sun, 1 Nov 2020 10:20:11 +0100 (CET), Michael Van Canneyt via
lazarus <[hidden email]> wrote:

>> QUESTION:
>> Is there a way in code to check if Forms is used?
>> So it can be used instead of {$IFDEF NOGUI}
>
>normally
>
>{$IF DECLARED(Forms)}
>or
>{$IF DECLARED(TForm)}
>
>should do the trick for you.
>

I created this command line program:

program Test;

begin
  Writeln('I will test the TForm check now:');
  {$IF DECLARED(TForm)}
    Writeln('TForm is declared...');
  {$ELSE}
    Writeln('Apparently TForm not declared');
  {$ENDIF}
  Writeln('I will test the Forms check now:');
  {$IF DECLARED(Forms)}
    Writeln('Forms is declared...');
  {$ELSE}
    Writeln('Apparently Forms not declared');
  {$ENDIF}

end.

When I run it in a console:

$ ./Test
I will test the TForm check now:
Apparently TForm not declared
I will test the Forms check now:
Apparently Forms not declared

However in the Lazarus code editor the lines inside the {$ELSE}
clauses are shown as disabled even though these are the ones actually
present and running in the build...


--
Bo Berglund
Developer in Sweden

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list


On Sun, 1 Nov 2020, Bo Berglund via lazarus wrote:

>> should do the trick for you.
>
> A quick test:
> It seems like there is a problem with this...
> I added this to the end of a random function:
>
>  {$IF DECLARED(TForm)}
>    Application.ProcessMessages;
>  {$ENDIF}
>
> Even though the project does not use Forms (Search/Find in Files in
> all project files does not find it) the code within the block is
> marked enabled and a quick compile succeeds.
>
> No file in the project declares Forms as a used unit.
> Same thing happens if I check for Forms in the code above...
>
> If I try to use the right-click/FindDeclarationOf on Processmessages
> pops up an error:
> class_SSRemoteServer.pas(530,5) Error: identifier not found:
> Application
>
> However, the app builds...
> So maybe this is a problem with the Lazarus code editor not being able
> to parse the {$IF DECLARED(TForm/Forms)} item?

I can't comment on this.

>
> To really check this I need to create a test app and run it in the
> debugger, I guess..
> In a command line program it should not generate code, right?

Yes.

Michael.
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Sun, 01 Nov 2020 11:48:54 +0100, Bo Berglund via lazarus
<[hidden email]> wrote:

>I created this command line program:
>
>program Test;
>
>begin
>  Writeln('I will test the TForm check now:');
>  {$IF DECLARED(TForm)}
>    Writeln('TForm is declared...');
>  {$ELSE}
>    Writeln('Apparently TForm not declared');
>  {$ENDIF}
>  Writeln('I will test the Forms check now:');
>  {$IF DECLARED(Forms)}
>    Writeln('Forms is declared...');
>  {$ELSE}
>    Writeln('Apparently Forms not declared');
>  {$ENDIF}
>
>end.
>
>When I run it in a console:
>
>$ ./Test
>I will test the TForm check now:
>Apparently TForm not declared
>I will test the Forms check now:
>Apparently Forms not declared
>
>However in the Lazarus code editor the lines inside the {$ELSE}
>clauses are shown as disabled even though these are the ones actually
>present and running in the build...

Forgot to state environment:
FPC 3.0.4
Lazarus 2.0.8
OS: Raspbian Linux on RPi4


--
Bo Berglund
Developer in Sweden

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list


On Sun, 1 Nov 2020, Bo Berglund via lazarus wrote:

> On Sun, 1 Nov 2020 10:20:11 +0100 (CET), Michael Van Canneyt via
> lazarus <[hidden email]> wrote:
>
>>> QUESTION:
>>> Is there a way in code to check if Forms is used?
>>> So it can be used instead of {$IFDEF NOGUI}
>>
>> normally
>>
>> {$IF DECLARED(Forms)}
>> or
>> {$IF DECLARED(TForm)}
>>
>> should do the trick for you.
>>
>
> I created this command line program:
>
> program Test;
>
> begin
>  Writeln('I will test the TForm check now:');
>  {$IF DECLARED(TForm)}
>    Writeln('TForm is declared...');
>  {$ELSE}
>    Writeln('Apparently TForm not declared');
>  {$ENDIF}
>  Writeln('I will test the Forms check now:');
>  {$IF DECLARED(Forms)}
>    Writeln('Forms is declared...');
>  {$ELSE}
>    Writeln('Apparently Forms not declared');
>  {$ENDIF}
>
> end.
>
> When I run it in a console:
>
> $ ./Test
> I will test the TForm check now:
> Apparently TForm not declared
> I will test the Forms check now:
> Apparently Forms not declared
>
> However in the Lazarus code editor the lines inside the {$ELSE}
> clauses are shown as disabled even though these are the ones actually
> present and running in the build...

Well, then the IDE codetools have an issue.

Michael.
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
On Sun, Nov 1, 2020 at 11:51 AM Michael Van Canneyt via lazarus
<[hidden email]> wrote:

> Well, then the IDE codetools have an issue.

It's a known issue, not yet fixed.

--
Bart
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] What to replace Application.Processmessages with?

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Sun, 01 Nov 2020 11:37:14 +0100
Bo Berglund via lazarus <[hidden email]> wrote:

> On Sun, 1 Nov 2020 10:20:11 +0100 (CET), Michael Van Canneyt via
> lazarus <[hidden email]> wrote:
>
> >> QUESTION:
> >> Is there a way in code to check if Forms is used?
> >> So it can be used instead of {$IFDEF NOGUI}  
> >
> >normally
> >
> >{$IF DECLARED(Forms)}
> >or
> >{$IF DECLARED(TForm)}
> >
> >should do the trick for you.  
>
> A quick test:
> It seems like there is a problem with this...
> I added this to the end of a random function:
>
>   {$IF DECLARED(TForm)}

Not yet supported by codetools, i.e. in the IDE. Codetools simply
evaluates "declared()" to true.

>     Application.ProcessMessages;
>   {$ENDIF}

Test compile by adding some invalid line like aaa;

Mattias
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus