Jeff Steinkamp 1 Posted November 24, 2022 I am returning to Delphi and Object Pascal after a 15+ year hiatus over in Visual Studio with C# and VB. I think the last IDE I used might have Delphi 2 or 3. So, working my way around this 10.4 monster has been somewhat of a challenge. I have built a File Download Dialog with a progress bar and some labels to show total byte count and a running total of bytes downloaded. I'm using the Indy IDHttp component with the SSL handler to fetch the files and the associated events. I am updating the UI with the Application.ProcessMessage pump, but I'm not sure this is the proper way to update a UI and maybe threading this is the proper solution. If that is the case, then can someone point me in the right direction on how to properly use threads as my google search have turned up a lot of 'mis-information' to say the least. This seems to work fine with a 25MB file, but I'm not sure how it will work with 350MB file!! I can upload my code if someone is interested. Share this post Link to post
aehimself 399 Posted November 24, 2022 As a general rule of thumb, never call Application.ProcessMessages by yourself. Let your thread "ping" back with updates from time to time with TThread.Synchronize, you can even have a TTimer in your VCL thread to poll updates from the Thread via public properties. Just make sure you are using some king of locking (TCriticalSection, TMonitor, mutexes, events, etc.) when reading from and writing to these variables. Share this post Link to post
Dalija Prasnikar 1405 Posted November 24, 2022 You can find simple demo how to use threads with Indy here: https://github.com/dalijap/code-delphi-thread-safety/tree/master/Part3/19 Indy This demo is using anonymous thread, but you can also use regular threads or TTask from Parallel Programming library, too. If you can post your code I can give you more detailed advice. 1 Share this post Link to post
Jeff Steinkamp 1 Posted November 25, 2022 4 hours ago, Dalija Prasnikar said: You can find simple demo how to use threads with Indy here: https://github.com/dalijap/code-delphi-thread-safety/tree/master/Part3/19 Indy This demo is using anonymous thread, but you can also use regular threads or TTask from Parallel Programming library, too. If you can post your code I can give you more detailed advice. I took a page out of this Indy demo and applied it to my code, and once I got the FileStream creating straightened out for the thread, it is functioning quite well indeed!. I have attached the file for that unit if you want to have a look and see if there is anything that can be done differently. FileDownload.dfm FileDownload.pas Share this post Link to post
Dalija Prasnikar 1405 Posted November 25, 2022 6 hours ago, Jeff Steinkamp said: I took a page out of this Indy demo and applied it to my code, and once I got the FileStream creating straightened out for the thread, it is functioning quite well indeed!. I have attached the file for that unit if you want to have a look and see if there is anything that can be done differently. It just needs few tweaks. First, you don't need Application.ProcessMessages anywhere - they have been commented out, but the whole point of threads is getting rid of those. So you can just forget about it 🙂 Next, this will work fine, but in case user closes the dialog before download completes already queued synchronization methods will access released form and crash. To prevent that, you need to add additional filed in Form declaration and OnCloseQuery event handler on the form. I also fixed try finally block inside thread as constructing HTTP instance can also fail (not likely event, but still), and in that case the cleanup was not proper one. I also added try..except block to show error message in case of failure. If the whole application is closed then anonymous threads can be killed at any time. If this is a possibility, then you might want to replace TThread.CreateAnyonymousThread with TTask.Run (without Start) from System.Threading as all running tasks will be waited for on application shutdown. FileDownload.pas FileDownload.dfm Share this post Link to post
Jeff Steinkamp 1 Posted November 25, 2022 8 hours ago, Dalija Prasnikar said: If the whole application is closed then anonymous threads can be killed at any time. If this is a possibility, then you might want to replace TThread.CreateAnyonymousThread with TTask.Run (without Start) from System.Threading as all running tasks will be waited for on application shutdown. Thanks for your updates!! I was concerned about this, and I will look into getting rid of the Anonymous Thread and replacing it. First, I will see if I can duplicate that behavior. I think this will suffice for my purposes and I should be able to use this in other projects that I am considering. Share this post Link to post
programmerdelphi2k 237 Posted November 25, 2022 (edited) hi @Jeff Steinkamp As "CreateAnonimous" return a "Thread" you can do it: create a Array (global or a list protected to multi-access) to store (reference, id, etc...) all thread (anonimous or not) created if using "protected list" (using TMonitor, TCriticalSection, TSemaphore, etc...) you can control it better, but I think that it's not necessary at all (see each situation in usage) if necessary, you can "remove" the thread reference in these list using "OnTerminate or other" when this thread is ended... if possible! when your form needs to be closed, you can scan this array and see if exists any thread on list and try terminate it, free it etc... this task can be done in "OnCloseQuery()", then, "OnClose()" is free to anothers tasks, you decide! I have done some like: function TerminateMyTasksFirstToLast(AStartFromFirst: boolean = false): integer; ... scan all array with thread reference stored and try end it... OnCloseQuery event: CanClose := (TerminateMyTasksFirstToLast() = 0); // if have any thread running... wait end it Edited November 25, 2022 by programmerdelphi2k Share this post Link to post