-
Content Count
1137 -
Joined
-
Last visited
-
Days Won
105
Posts posted by Dalija Prasnikar
-
-
1 hour ago, David Schwartz said:I understand from the first reply that the three objects need to be created dynamically inside the task. That's fine.
A different post about this general topic suggested a fork/join approach using a counter object to know when it's finished. That's fine, too, although it may be more complicated than I need.
Creating separate objects would be my preferred approach, they are not that heavy to have significant impact on performance.
1 hour ago, David Schwartz said:Another reply here pointed out ExecuteAsync which I had not noticed (although I looked for Async...something), and it has some very interesting properties that also suggest the fork/join approach might have a simpler solution with it. In particular, I like the options that the anonymous methods offer in conjunction with the parameters that say whether the code should run in the main form's thread or the current thread.
ExecuteAsync is .... I have no words for describing it... maybe some people would like it, but for me it is useless addition. If you want to run rest it in the background thread simplest code is to just run the whole thing in background thread and then synchronize only if you need to synchronize some piece of code. With Execute you get clean code under your control where it is obvious what runs where and how you need to handle things, with ExecuteAsync you first need to learn how to use it properly. I would forget about it as it does not offer any advantages.
1 hour ago, David Schwartz said:But every other post here added a warning about this or that, and it got confusing with the Execute vs. ExecuteAsync. The entire discussion seems like it could have been reduced to one or two short code examples like the above, so thank you Dalija.
I am glad if it helped to give you some insight, because I was confused about what you are aiming at.
1 hour ago, David Schwartz said:(I'd post something on SO, but it seems a lot of my questions get downvoted or locked for being "off-topic". They're Delphi questions -- I don't get what's "off-topic" about Delphi questions in a forum intended for Delphi questions. Now I get warnings from SO saying my account is close to being locked because of the "low-quality" of my questions. I used to have nearly 2000 points and 45 badges before something short-circuited and SO's support people denied there was a problem. All of that "bling" just disappeared. So I don't spend much time there any more. I'm also very hesitant to post any more questions. The last one I posted got lots of opinions, and no definitive answers.)
You can ask only very specific questions on Stack Overflow. For instance your initial question here would be definitely off topic on Stack Overflow. If you can create some minimal code example something in line what I have posted here as example, then you can aske whether you are doing it correctly and whether it is thread safe. It is also good to point to specific parts of the code you are not sure about. When it comes to thread safety it depends on the actual code and sometimes people don't add enough code. On the other hand adding too much code is also a problem because it is harder to get clear picture id there is plenty of code. For instance, if you need to populate UI, you don't need to show 50+ lines of UI related code. One is enough.
The quality of answers also very much depends on the quality of the question. If answering requires a lot of guessing you will less likely get good answers.
1 hour ago, David Schwartz said:My only resources for help have been this place, SO, and Google. I truly do appreciate all of the help that's available here, and it's mostly because I value the level of mastery everybody here has. I know I can be a PITA at times because I often have very clear pictures in my head of what I'm looking for, I just have trouble expressing things clearly. We programmers are often no better at describing things in our heads than our clients, eh? 🙂
Few lines of code speak better than words 🙂 Don't describe your code, write it - even if it is just a rough concept. Then build the rest of the explanation on top of that.
-
1
-
-
3 hours ago, David Schwartz said:Doesn't anybody do anything useful with multi-threading REST API calls besides incrementing integers?
I don't understand what is your problem. You asked whether those classes are safe, we answered they are not. Every thread needs to have dedicated object instance for each one - client, request, response.
Even if you use ExecuteAsync, you cannot share that instance.
So basic example would be
for i := 0 to Data.Count-1 do begin RunRest(Data[i]); end; procedure RunRest(const s: string); begin TTask.Run( procedure var Client, Response, Request... begin Client := TRESTClient.Create(s); try Response := TRESTResponse.Create(Client); Request := TRESTRequest.Create(Client); // other rest setup... Request.Execute; // process Response, if needed you can do that in Synchronize call - if you are interacting with GUI then you definitely need to Synchronize here finally Client.Free; end; end); end;
-
Konopka VCL Controls are not available for Community Edition. You need to have purchased license (see under Subscription) to get them: https://getitnow.embarcadero.com/KonopkaControls-270-6.2.3/
-
TFunc is anonymous method, which are backed by interface. So GUID you get from field type is not for ITestA,, but for TFunc<ITestA>.
I don't think you can get generic part out from parameterized type. In theory TFunc has Invoke method, so if you could get information on its result type, you would have ITestA. But I couldn't get Invoke information out of RTTI.
The real question here is what you are actually trying to do. Your test code is obviously just a test - you already know that TForm1 MyField works with ITestA, so if you can make small test case for your actual use case, maybe there is a way to get information you need.
For instance if your form would be generic, you would more easily get what you need because you would have T to work with
TForm1<T> = class(TForm) private MyField:TFunc<T>; end;
-
1
-
-
56 minutes ago, David Schwartz said:Are the Delphi TRESTClient / TRESTRequest / TRESTResponse components thread-safe?
If so, can I create just one TRESTClient and then multiple Request/Response pairs linked to it? Or do I need duplicate Client objects as well?
None of those components are not thread-safe. They can be used in background threads, but each thread needs to have their own instances. Yes, you need separate client objects for each thread, too.
56 minutes ago, David Schwartz said:If the data collected in each thread is in a TStringlist, then is it safe to save it to disk using a unique name with sl.SaveToFile(...)? (There's no contention for the files until after they've all completed.)
If the StringList is not shared and you generating unique file name is coordinated between threads, so there cannot be any overlap, then it is safe to save inside thread.
-
2
-
-
15 minutes ago, David Heffernan said:Correct. But there are many possible ternary operators. It's the conditional operator, which is an example of a ternary operator.
Right... I completely misinterpreted what you were saying. I guess it is "I am reading words, but their meaning is not arriving in my brain" day...
-
1
-
-
30 minutes ago, David Heffernan said:We should stop referring to the conditional operator as "the" ternary operator. A ternary operator is one with three operands. Just as a binary operator is one with two operands.
I think it is called ternary because there are three expressions in play.
-
If anyone is interested in upcoming version, there will be a webinar https://register.gotowebinar.com/register/4959183786599768588
-
4
-
-
1 hour ago, Stefan Glienke said:If you are a seasoned Delphi developer you know that new features are not usable for like half a decade or so...
I always had high hopes that by 10.7 everything will work as intended. Now we will have to wait until Delphi 17.
-
6
-
-
4 minutes ago, David Heffernan said:Nobody is suggesting that. The question is for people that are wanting to use the new feature to take advantage of its benefits.
I have seen plenty of developers (not only Delphi) jumping on new features and rewriting code for no good reason. It never hurts explicitly stating even the obvious things
-
3
-
-
35 minutes ago, Zoë Peterson said:I absolutely do not understand why that's the only approach anyone's used.
I keep asking myself the same question over and over again. Let me know if you find the answer 😕
-
15 hours ago, Zoë Peterson said:Are there any object-to-JSON serialization libraries available that work with published properties (not public, not fields) and which allow customizing the serialization externally to the class? Dalija talked about this in her "When in Rome" series (https://dalijap.blogspot.com/2021/04/when-in-rome-do-as-romans-do-part-i.html) but didn't point to an alternative that worked that way. Any license is fine, though open source of some sort would be preferable.
I am working on one, but it is work in progress. Intention is to make this during follow up series of blogposts. Since I am quite busy at the moment, I am not sure when will this see the light of day.
I already have such framework written in Swift, so most of the mental work is finished, but there is still a lot to do beyond merely translating it to Delphi, as it does not have all bells and whistles fully in place.
-
5 minutes ago, mvanrijnen said:Only the updates did not fix the problems they supposed to do.
LSP/Codecompletion malfunctioning.
If i look the the bugs which are still open and/or being reported it does not sound like a reasonable finished product.
Like delivering a car from which the weels unexpected fall of.
If you'r lucky you don't have a problem, i you'r unlucky you end the day after a few hours withouth wheels.
Refactoring which stops working, suddenly freezes of the IDE, suddenly exiting of the IDE, making a mess of project files etc etc.
Inserting events wrong in the sourcecoude (doubleclicking an event in the property inspector), i can go on and on.
Unfortunately, not all bugs get fixed in updates.
LSP is a complex feature and it will take time to solve all issues. That is why you can still use Classic Code completion if the LSP is too troublesome.
-
1 hour ago, mvanrijnen said:When we get a decent version of 10.4 ?
10.4 got all the updates it was supposed to. There is always a chance it may receive some additional hotfix, for some really, really critical issue, but not very likely.
-
5 hours ago, Darian Miller said:This future releases page has everything I know about RAD Studio 11 (formerly known as 10.5) that can be said publically. https://github.com/ideasawakened/DelphiKB/wiki/Future-Releases-for-RAD-Studio-and-Delphi
Unfortunately, that roadmap is pretty much obsolete, there is no newer one and anyone who knows what is cooking is not at liberty to say.
-
2 hours ago, Remy Lebeau said:I always advise people NOT to rely on the TThread destructor terminating and waiting on the running thread, as doing so has been the source of many headaches in the past. Terminating and waiting on the running thread should always be an explicit operation before destroying the TThread object, IMHO.
Maybe this has been source of trouble in the past, but TThread destructor terminates thread and waits for it at least since Delphi 7.
Under some circumstances code might require explicit termination and waiting before calling destructor. For instance if destructor is overridden and can destroy fields that are used by the thread, but if the order of destruction is important, I would still prefer code that handles proper shutdown sequence inside such overridden TThread class than handling it from the outside code. When it is handled from the outside there is always greater possibility that someone will forget to explicitly terminate and wait.
-
Animation is not working because thread is doing very little work besides queuing work to the main thread. This gives very little chance to the main thread to do anything besides processing the queued work and repaint animation. This is matter of timing so it is not surprising that you have different behavior on different platforms.
You can either use ProcessMessages to force main thread message processing and repainting the animation, or you can put thread to sleep for short period of time. However, sleeping will slow down the whole process, so you don't want to call it at every iteration.
Following code works without issues.
There are some additional notes, some already mentioned by @Remy Lebeau
First, I have changed StopThread procedure to just call FreeAndNil(FMyThread) - freeing the thread will also call Terminate and WaitFor - this is why it causes the deadlock is you are using Synchronize. Niling the thread is there so you can click the button again otherwise you would leak the thread.
If the thread is already running you will not be able to start the thread again, but you will be able to do so after the first thread is finished. NotifyComplete procedure will also call StopThread to release the thread because it makes no sense to keep dead thread around.
Calling TThread.Queue(TThread.CurrentThread will discard any queued events after the thread is dead. In this example it is important to do so, because form is closing any we don't want to run any already queued events after form is released as this would cause AV. If there is something that needs to be always executed then such code should be in OnTerminate event. When it comes to anonymous method variable capture, they will be captured and their lifetime will be extended, but that only means variable will be accessible, but does not guarantee that the content (object) will be alive, you can only safely use variables of value types and managed types. For others, you need to be sure that they will be alive as long as anonymous method is running. In this case ListView1 and Button2 will not be alive when the form is closed.
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin StopThread; end; procedure TForm1.StopThread; begin FreeAndNil(FMyThread); end; procedure TForm1.NotifyComplete; begin AniIndicator1.Visible := False; AniIndicator1.Enabled := False; ListView1.EndUpdate; ListView1.Enabled := true; StopThread; end; procedure TForm1.Button2Click(Sender: TObject); begin if Assigned(FMyThread) then Exit; AniIndicator1.Visible := True; AniIndicator1.Enabled := True; ListView1.Enabled:=false; ListView1.BeginUpdate; FMyThread:=TThread.CreateAnonymousThread(procedure () var I: Integer; Total: Integer; begin Total := 0; for I := 1 to MaxValue do begin TThread.Queue(TThread.CurrentThread, procedure () begin ListView1.Items.Add.Text := 'Th: ' + I.ToString; Button2.text:= i.tostring; end); if Application.Terminated then begin break; end else begin if i mod 10 = 0 then Sleep(1); end; end; TThread.Queue(TThread.CurrentThread, procedure() begin ListView1.Items.Add.Text := 'Thread: ' + Total.ToString; NotifyComplete; end); end); FMyThread.FreeOnTerminate := False; FMyThread.Start; end;
-
1
-
-
You have problems because you are not changing your original code with just replacing Synchronize with Queue.
In previous code you had Synchronize inside loop and now you have loop inside Queue. Go back to your original code and just use Queue instead of Synchronize.
-
Now you have completely removed threads. I meant like this: in places where you are calling TThread.Synchronize you should use TThread.Queue
FMyThread:=TThread.CreateAnonymousThread(procedure () begin ... TThread.Queue(TThread.CurrentThread, procedure () begin ... end); ... end; TThread.Queue(TThread.CurrentThread, procedure () begin ... end); end);
-
You have a deadlock.
Waiting for background thread in main thread that uses Synchronize is recipe for disaster. Namely, when you start waiting you are blocking main thread until thread is finished, but when thread encounters Synchronize it will try to execute that code in the context of the main thread, but since main thread is on hold at that time Synchronize will never be able to run and finish.
You should use TThread.Queue instead.
-
2
-
-
Processing messages for whole application happens in one place. WM_TIMER is low priority message and it will be dispatched only after all higher priority messages are dispatched. The fact that WM_TIMER messages are not being processed fast enough means that you application is either flooded with messages or is doing to much work in main thread, including code called with TThread.Synchronize and TThread.Queue.
Changing from TPanel to TObject with allocated handle should not have any impact on processing speed.
Also using WM_TIMER for progress is usually poor approach, it is better that you send status from the thread when you have some significant change to show.
Additionally, if you are sending messages from OnTerminate event then you don't need to wait on thread (also freeing the thread will also wait).
It is hard to say more without having reproducible example.
-
1
-
-
20 minutes ago, Fabian1648 said:I looked at your zip. So if I understand correctly:
- I don't modify in "Project > deployment" the icons defined by Delphi via "Project > options"
- I add the files of the additional icons in "Project > deployment"
- I modify the manifest.xml file
Is this correct?
1. You add your own icons of appropriate sizes
2. Yes, you add additional icons in Project > deployment
3. Modifying manifest.xml is probably not even needed. AFAIK only difference between Android Studio manifest and Delphi manifest is in android:RoundIcon declaration and as far as I know round icon is not mandatory. However, you can also add that one just in case. Problem with Android is that there is plethora of devices with customized OS-es and some may require round icon for better UX.
-
1
-
3 hours ago, Dave Nottage said:There is no need to uncheck those. Actually, those are still needed for supporting older Androids (unless you set minimum API to 26)
Procedure would be - fill all icons you can through Project > Options > Application > Icons, then only add additional icons that cannot be set through Delphi.
There is open issue requesting support for adaptive icons https://quality.embarcadero.com/browse/RSP-21335 and I attached zip with default icons resources created by Android Studio new project template. This makes it easier to see which icons need to be added manually and how they should look like.
-
4
-
-
11 minutes ago, PeterPanettone said:I wonder whether ROUNDED CORNERS will be compatible with the Delphi IDE. 😊
Windows XP, Vista and Windows 7 had round corners... I guess that will not be an issue 😃
Is there an elegant way in Delphi to prevent instantiating a class?
in Algorithms, Data Structures and Class Design
Posted
You cannot make such singleton in Delphi. Public TObject constructor will be always visible and you cannot hide it,
The only way to disable access to the constructor is to define singleton API as interface and have public factory method that returns interface, and then put class implementation inside implementation section of the unit making it inaccessible to the outside world.