Recent

Author Topic: Synchronize not working  (Read 27526 times)

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 762
Re: Synchronize not working
« Reply #60 on: November 28, 2021, 06:06:46 am »
Yeah, both solutions have their pros and cons. Blocking main thread is also bad idea and can cause many problems. Especially, when application has GUI. Solutions without threads is possible. Using timer events for example. They're async, i.e. don't block main thread and they allow us to implement something like "do something after x milliseconds".
29.12.2021 - migration to DynamicData 4.1 is completed - complete overhaul of data access driver.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 13 years old.

Warfley

  • Hero Member
  • *****
  • Posts: 814
Re: Synchronize not working
« Reply #61 on: November 28, 2021, 03:52:11 pm »
Yeah I think what cannot be stressed enough is, don't use sleep in the main thread of a GUI application. GUI applications (or to be more general interactive applications) are event based. It is generally a sign of bad design if one tries to perform serialzed operations in an event based system.

MarkMLl

  • Hero Member
  • *****
  • Posts: 4163
Re: Synchronize not working
« Reply #62 on: November 28, 2021, 05:09:12 pm »
Yeah I think what cannot be stressed enough is, don't use sleep in the main thread of a GUI application. GUI applications (or to be more general interactive applications) are event based. It is generally a sign of bad design if one tries to perform serialzed operations in an event based system.

One observation on that. In Delphi, certainly the older versions I used before switching to Lazarus, a procedure called by e.g. OnActivate could loop reading the keyboard provided that it did an APM. In Lazarus I've never been able to get anything comparable working, which has complicated software into which one can type commands enormously.

Please don't ask for a detailed example etc., it would take me days of work to work out the exact conditions.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Warfley

  • Hero Member
  • *****
  • Posts: 814
Re: Synchronize not working
« Reply #63 on: November 28, 2021, 07:43:38 pm »
I encountered the exact same problem when I tried to get my STAX working on forms, I was searching for the best event to start the executor. OnActivate has a pretty weird behavior, it looks to me as if you loop in it, focusing doesn't work anymore
Found the solution to be is to start a timer with a small interval in whoms tick event to do the serialized work.

MarkMLl

  • Hero Member
  • *****
  • Posts: 4163
Re: Synchronize not working
« Reply #64 on: November 28, 2021, 08:18:14 pm »
Glad it's not just me :-) I wasn't quite using OnActivate... in the Delphi days I used form creation to put a custom message on the queue which caused a procedure to be called (and in this case loop with an APM in it) once the message loop was running. These days I use a QueueAsyncCall() to do approximately the same thing.

It /almost/ worked, except- as in your case- when e.g. a dialog(ue) had to be handled. I ended up with a thoroughly convoluted alternative where the keyboard reader and a great deal of the program itself runs in background threads... it works but I'm not exactly happy with it particularly considering the amount of work it took.

I can't remember the exact details by now, but I quite simply couldn't find a standard component which handled a typed-in command from the user sensibly.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 762
Re: Synchronize not working
« Reply #65 on: November 29, 2021, 09:43:31 am »
It's always good thing to understand, that VCL - is just OOP wrapper around windows User32 library. So OnActivate - is wrapper around WM_ACTIVATE. In most cases it's important to know, whether message is sync or async, i.e. if it's sent or posted. If sender needs message result, then message should be sent. And in this case blocking it's handler means blocking sender execution. Overall there are 3 types of messages: 1) Posted, that is async and therefore sent via message queue 2) Sent, that is sync (i.e. window proc is called directly) for the same thread, but can be async for other thread 3) Message, that is always sync, because it's sent via calling window proc directly. It's true for something like WM_CREATE. At least in older Windows versions.
« Last Edit: November 29, 2021, 09:46:06 am by Mr.Madguy »
29.12.2021 - migration to DynamicData 4.1 is completed - complete overhaul of data access driver.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 13 years old.

MarkMLl

  • Hero Member
  • *****
  • Posts: 4163
Re: Synchronize not working
« Reply #66 on: November 29, 2021, 09:59:12 am »
It's always good thing to understand, that VCL - is just OOP wrapper around windows User32 library. So OnActivate - is wrapper around WM_ACTIVATE. In most cases it's important to know, whether message is sync or async, i.e. if it's sent or posted. If sender needs message result, then message should be sent. And in this case blocking it's handler means blocking sender execution. Overall there are 3 types of messages: 1) Posted, that is async and therefore sent via message queue 2) Sent, that is sync (i.e. window proc is called directly) for the same thread, but can be async for other thread 3) Message, that is always sync, because it's sent via calling window proc directly. It's true for something like WM_CREATE. At least in older Windows versions.

Yes, and that also applies to the one-shot message that I was using to kick stuff off when I was using Delphi.

I'd be surprised if anybody thought this merited serious investigation, and am not prepared to do it myself only to be told that the LCL was already working properly. But I suppose that the interesting thing is the way that the LCL (on Linux) /almost/ works in the way that Warfley and I hoped, with the exception of the focus issue.

MarkMLl

MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 4005
  • Compiler Developer
Re: Synchronize not working
« Reply #67 on: November 29, 2021, 02:01:11 pm »
Yes sleep(0) will not reduce the CPU load, thats not the goal, it just yields to other processes so you don't starve them. If you want to actually reduce CPU usage you need to actually slow down your program (e.g. with sleep > 0)
Why use sleep when you can suspend and use resume.
They have no load on the processor.

Suspend and Resume should not be used: you might suspend the thread while inside a critical section that is then never released until the thread is resumed and if the thread that controls the suspension and resuming then uses this critical section as well you'll have a deadlock. If you want to pause a thread until something from outside happens then wait on an event (which won't result in CPU load as well).

I thought the use of sleep or application.processmessage was considered negative from a programming perspective.
Is sleep used in professional programs?
Application.ProcessMessages is usually negative now because today's OSs support multi-threading and implement preemptive multitasking.  Application.ProcessMessages is something that was often necessary in the versions of Windows that required cooperative multitasking, their scheduler depended on the program voluntarily relinquishing the CPU to the scheduler and processing messages which was the gateway to those O/Ss schedulers regaining control.

Application.ProcessMessages still has its place if you're doing some long running operation without using threads. E.g. updating a progress bar and listening for the click of a cancel button more often than not can be done without a thread (especially if the remainder of the UI is disabled).

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 762
Re: Synchronize not working
« Reply #68 on: November 29, 2021, 02:08:04 pm »
Yes, and that also applies to the one-shot message that I was using to kick stuff off when I was using Delphi.

I'd be surprised if anybody thought this merited serious investigation, and am not prepared to do it myself only to be told that the LCL was already working properly. But I suppose that the interesting thing is the way that the LCL (on Linux) /almost/ works in the way that Warfley and I hoped, with the exception of the focus issue.

MarkMLl
Back in old times I had very good Visual Basic book, that wasn't about Visual Basic only - it was also about many Win32 tips and tricks.
29.12.2021 - migration to DynamicData 4.1 is completed - complete overhaul of data access driver.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 13 years old.

MarkMLl

  • Hero Member
  • *****
  • Posts: 4163
Re: Synchronize not working
« Reply #69 on: November 29, 2021, 02:42:15 pm »
Suspend and Resume should not be used: you might suspend the thread while inside a critical section that is then never released until the thread is resumed and if the thread that controls the suspension and resuming then uses this critical section as well you'll have a deadlock. If you want to pause a thread until something from outside happens then wait on an event (which won't result in CPU load as well).

Thanks for the reminder. I still use them for one very specific purpose- temporarily stopping a thread's execution loop until work is available- but I think that could be changed to use an event without hassle.

Quote
Application.ProcessMessages still has its place if you're doing some long running operation without using threads. E.g. updating a progress bar and listening for the click of a cancel button more often than not can be done without a thread (especially if the remainder of the UI is disabled).

Pretty much indispensable TBH, since it's unlikely that the GUI execution model will be changed at this late stage. But one does have to be careful about re-entry: e.g. where something being invoked by a thread using Application.QueueAsyncCall() incautiously does an APM to make sure that debug output shows up promptly.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 915
Re: Synchronize not working
« Reply #70 on: November 29, 2021, 06:59:54 pm »
Application.ProcessMessages is good for just one thing: keeping the GUI alive when doing lots of processing in the main thread. My initial reaction was about, that it doesn't fix your application freezing.

The main issue is resources. You can try to maximize performance by allocating everything you're going to need at startup, or you can allocate and free things on demand. If it is just small pieces of memory, that's easy and fast. But quite a lot of things have to ask for access, from the OS, a library or background process. The obvious ones are files and sockets. Like, the connection to a database.

So, if you're not running just a single loop with pre-allocated objects, but do a lot of different tasks, that require a lot of Create and Free, it is very likely that your application starts freezing randomly. Application.ProcessMessages won't help here. Some well-placed Sleep(0) calls probably will. And yes, you should probably split them up in different processes and/or threads.

That's why you make a single connection to a database and reuse that. And use transactions.

The MS Thread architecture is basically flawed in that it relies on shared memory and that named pipes or other easy inter-process communication methods are barely supported. It's fine to use sockets for inter-process communication, but not between threads, as you need another thread to handle the socket.

It seems like a good thing to put critical sections around every dubious block of code, use lock .. unlock wherever it looks useful and use synchronize to update that single copy of the variable. Which essentially serializes your application and creates a lot of potential race conditions.

Blocking threads are another matter. If I look in Task Manager, I see that there are 217 processes and 3589 treads running, and 116541 handles in use. Most of those threads are blocked and waiting for input. That's totally fine. And most of those handles are locks on dynamically allocated resources. So, there are a lot of resources allocated (like those files and sockets) through processes that cannot immediately respond to changes. They poll them in a loop, or only use them synchronized (wait for completion). Those need enough CPU time to complete the request and/or run through a loop polling them.

So, it doesn't matter if you serialize and synchronize everything, but then threads make no sense. In all other cases, asynchronous requests make a lot of sense, but you would want a tread waiting for completion for all requests. On Linux this is a totally different matter.
« Last Edit: November 29, 2021, 08:30:30 pm by SymbolicFrank »

MarkMLl

  • Hero Member
  • *****
  • Posts: 4163
Re: Synchronize not working
« Reply #71 on: November 29, 2021, 07:20:32 pm »
Or put another way, "It's complicated" :-)

On Linux you can, of course, use unix domain sockets with the standard API. But I'm dismayed by the number of people who quite simply grab a multilayer protocol on top of an inet domain socket and start moving enormous blocks of XML or JSON around.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 2753
Re: Synchronize not working
« Reply #72 on: November 29, 2021, 07:42:00 pm »
Application.ProcessMessages still has its place if you're doing some long running operation without using threads. E.g. updating a progress bar and listening for the click of a cancel button more often than not can be done without a thread (especially if the remainder of the UI is disabled).
IMO, if some activity takes long enough that it requires a progress bar then, that activity should be done by a thread other than the GUI thread and, that other thread can easily post a message to the GUI thread informing it of the need to update the progress bar and what its new value should be.

IOW, IMO, a long running operation should be handed to a thread that is not the GUI thread.  The GUI thread should not be "indulging" in those things (except for proof-of-concept and throw away programs - and even then.)  Allowing a GUI thread to perform time consuming operations is just asking for trouble and, Application.Process messages is just a narcotic to alleviate pain instead of a cure.
FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 814
Re: Synchronize not working
« Reply #73 on: November 30, 2021, 10:24:21 am »
There are some reasons to avoid Threading, one being that threads can make the code much more complex (especially if you have to start implementing thread safe datastructrues and/or events).
That said, Application.ProcessMessages is more a hotfix rather than a real solution and has many problems. E.g. A short running function calls Application.ProcessMessages, an event causes a long running function to run. Even if that long runing function calls Application.ProcessMessages, the short running function will not terminate until the long running function terminates, resulting in a massive waste of time.

This is exactly why I build STAX earlier this year. But this would require mapping the APIs to STAX (which could internally be done using threads) but this of course having to implement those yourself defeats the whole "single threaded is simpler" argument.
But when implemented thourughly (like in other languages s.a. Python, C#, JS, C++) with lots of API support, co-routines can make life much easier and there is a reason they are so popular in those languages.
« Last Edit: November 30, 2021, 10:26:57 am by Warfley »

 

TinyPortal © 2005-2018