I have a thread which calls functions of certain form to update this form. When task is done, thread updates form with results, using Synchronize and it all works fine while the program is running.
The problem happens when the thread is running and I close the program I got access violation. It was caused by thread updating form which was already released. After rearranging order of form creation (calls to Application->CreateForm) it worked fine because now the form that holds thread code is created before form that is updated. It seems that order of destruction is reverse to creation order.
I also added some code in form destructor to make sure thread is terminated if form is destroyed before form with the thread code. So rearranging form creation order and/or code in form destructor solves the problem.
But I have 3 questions:
What is the order in which created forms are destroyed? Is it reverse of the creation order as I assume now?
Is there a better way to do the above task - update form GUI items after thread is done processing data. Right now I do it from thread itself using Synchronize but someone experienced with threads may have better idea. One other idea I had was to even remove a bunch of CreateForm generated by compiler and create them manually, only create main form using CreateForm to better control order of destruction (as suggested by Rob Kennedy - http://pages.cs.wisc.edu/~rkennedy/createform).
How expensive is dynamic form creation/destruction in typical application? Is it better to use form Hide and keep in memory or destroy it on close?
When you create a component with an Owner, the Owner adds your component to its list of components that it owns. That happens in this code:
procedure TComponent.Insert(AComponent: TComponent);
begin
if FComponents = nil then FComponents := TList<TComponent>.Create;
FComponents.Add(AComponent);
if FSortedComponents <> nil then
AddSortedComponent(AComponent);
AComponent.FOwner := Self;
end;
As you can see the component is added to the end of the list.
When the owner is destroyed, it calls DestroyComponents:
procedure TComponent.DestroyComponents;
var
Instance: TComponent;
begin
FreeAndNil(FSortedComponents);
while FComponents <> nil do
begin
Instance := FComponents.Last;
if (csFreeNotification in Instance.FComponentState)
or (FComponentState * [csDesigning, csInline] = [csDesigning, csInline]) then
RemoveComponent(Instance)
else
Remove(Instance);
Instance.Destroy;
end;
end;
As you can see, the loop processes the last member first. So, components are destroyed in reverse order.
Personally I would not rely on destruction order. If the form needs to be sure that the thread is terminated before the form is destroyed, I would write code in the form's destructor to enforce that.
Using Synchronize is a perfectly respectable solution to many problems. Whether or not it's the best solution to your problem is impossible me to say because you have not fully described your problem.
How expensive is dynamic form creation/destruction in typical application?
Not very. Typically forms are shown in response to user interaction. Programs can create forms a lot faster than users can process them. So dynamically creating forms is seldom a problem. If you wanted to create and destroy thousands of forms a second that might be a problem. But that would be bizarre.
Related
I am working on small monitoring application which will have some threads for communication with some devices via SNMP, TCP, ICMP, other threads have to perform some calculations.
All this result I have to output in GUI (some Forms or TabSheets).
I am thinking about next possibilities:
use Synchronize from every worker thread:
use shared buffer and windows messaging mechanism. Thread will put message in shared buffer (queue) and will notify GUI with windows message.
use separate thread which will listen for Synchronization primitives (Events, Semaphores, etc) and use again Synchronize, but only from GUI-dedicated thread only, or Critical Section on GUI to display message.
UPDATE: (Proposed by one workmate) use shared buffer and TTimer in main form which will check periodically (100-1000 ms) shared buffer and consuming, instead of windows messaging. (Does it have some benefit over messaging?)
Other?
Dear experts, please explain what is the best practice or what are the advantages and disadvantages of exposed alternatives.
UPDATE:
As idea:
//shared buffer + send message variant
LogEvent global function will be called from everywhere (from worker threads too):
procedure LogEvent(S: String);
var
liEvent: IEventMsg;
begin
liEvent := TEventMsg.Create; //Interfaced object
with liEvent do
begin
Severity := llDebug;
EventType := 'General';
Source := 'Application';
Description := S;
end;
MainForm.AddEvent(liEvent); //Invoke main form directly
end;
In Main Form, where Events ListView and shared section (fEventList: TTInterfaceList which is already thread-safe) we'll be:
procedure TMainForm.AddEvent(aEvt: IEventMsg);
begin
fEventList.Add(aEvt);
PostMessage(Self.Handle, WM_EVENT_ADDED, 0, 0);
end;
Message handler:
procedure WMEventAdded(var Message: TMessage); message WM_EVENT_ADDED;
...
procedure TMainForm.WMEventAdded(var Message: TMessage);
var
liEvt: IEventMsg;
ListItem: TListItem;
begin
fEventList.Lock;
try
while fEventList.Count > 0 do
begin
liEvt := IEventMsg(fEventList.First);
fEventList.Delete(0);
with lvEvents do //TListView
begin
ListItem := Items.Add;
ListItem.Caption := SeverityNames[liEvt.Severity];
ListItem.SubItems.Add(DateTimeToStr(now));
ListItem.SubItems.Add(liEvt.EventType);
ListItem.SubItems.Add(liEvt.Source);
ListItem.SubItems.Add(liEvt.Description);
end;
end;
finally
fEventList.UnLock;
end;
end;
Is there something bad? Main Form is allocated ONCE on application startup and Destroyed on application exit.
Use Synchronize from every worker thread
This would probably be the simplest approach to implement, but as others have indicated will lead to your IO threads being blocked. This may/may not be a problem in your particular application.
However it should be noted that there are other reasons to avoid blocking. Blocking can make performance profiling a little trickier because it effectively pushes up the time spent in routines that are "hurrying up and waiting".
Use shared buffer and windows messaging mechanism
This is a good approach with a few special considerations.
If your data is extremely small, PostMessage can pack it all into the parameters of the message making it ideal.
However, since you make mention of a shared buffer, it seems you might have a bit more data. This is where you have to be a little careful. Using a "shared buffer" in the intuitive sense can expose you to race conditions (but I'll cover this in more detail later).
The better approach is to create a message object and pass ownership of the object to the GUI.
Create a new object containing all the details required for the GUI to update.
Pass the reference to this object via the additional parameters in PostMessage.
When the GUI finishes processing the message it is responsible for destroying it.
This neatly avoids the race conditions.
WARNING: You need to be certain the GUI gets all your messages, otherwise you will have memory leaks. You must check the return value of PostMessage to confirm it was actually sent, and you may as well destroy the object if not sent.
This approach works quite well if the data can be sent in light-weight objects.
Use separate thread ...
Using any kind of separate intermediate thread still requires similar considerations for getting the relevant data to the new thread - which then still has to be passed to the GUI in some way. This would probably only make sense if your application needs to perform aggreagation and time-consuming calculations before updating the GUI. In the same way that you don't want to block your IO threads, you don't want to block your GUI thread.
Use shared buffer and TTimer in main form
I mentioned earlier that the "intuitive idea" of a shared buffer, meaning: "different threads reading and writing at the same time"; exposes you to the risk of race conditions. If in the middle of a write operation you start reading data, then you risk reading data in an inconsistent state. These problems can be a nightmare to debug.
In order to avoid these race conditions you need to fall back on other synchronisation tools such as locks to protect the shared data. Locks of course bring us back to the blocking issues, albeit in a slightly better form. This is because you can control the granularity of the protection desired.
This does have some benefits over messaging:
If your data structures are large and complex, your messages might be inefficient.
You won't need to define a rigorous messaging protocol to cover all update scenarios.
The messaging approach can lead to a duplication of data within the system because the GUI keeps its own copy of the data to avoid race conditions.
There is a way to improve the idea of shared data, only if applicable: Some situations give you the option of using immutable data structures. That is: data structures that do not change after they've been created. (NOTE: The message objects mentioned earlier should be immutable.) The benefit of this is that you can safely read the data (from any number of threads) without any synchronisation primitives - provided you can guarantee the data doesn't change.
The best approach is to use a GDI custom message and just call PostMessage() to notify the GUI.
type
TMyForm = class(TForm)
.
.
.
private
procedure OnMyMessage(var Msg: TMessage); message WM_MY_MESSAGE;
procedure OnAnoMessage(var Msg: TMessage); message WM_ANO_MESSAGE;
.
.
PostMessage(self.Handle,WM_MY_MESSAGE,0,0);
See this great article for full explanation.
This is a lighter/faster approach to rely on the OS internal features.
I have a unit with an initialization and finalization section. This unit contains a complex object which is instantiated in the initialization and destroyed in the finalization. However, this object also contains an ADO Connection. That makes it an issue when using this across threads, because ADO is COM, and needs to be initialized for every thread.
This is how I currently handle this global object instance:
uses
ActiveX;
...
initialization
CoInitialize(nil);
_MyObject:= TMyObject.Create;
finalization
_MyObject.Free;
CoUninitialize;
end.
This only works on the main thread. Any other thread wouldn't be able to access it, and will return an exception CoInitialize has not been called.
How do I get around this to make this unit thread-safe? I would need a way to hook every creation/destruction of any thread created, and each thread would need to refer to a different instance of this object. But how to go about doing so?
Well, as you already say yourself, each thread needs to call CoInitialize separately. And in addition, each thread needs to have its own ADOConnection too.
I think you need to leave the idea of using the single global object/connection from that unit. Just repeat that object creation and destruction in each thread. When the thread types are different, then you could design a base thread class on top of them. If the object is too big (has overhead with regard to the thread) or does not 'fit' completely in the thread, then split the object design.
For now, your question sounds like just wanting to keep convenience, but if it is really necessary to centralize the ADO connection involvement, then maybe you could implement multi-cast events for the connection events of both main thread and the other threads. Logging in should not be a problem for successive connections: just store the login values and feed them to the threads.
While another design might be a better solution, you can declare _MyObject as threadvar to have a separate instance for each thread. In addition you can move the CoInitialize/CoUnitialize into the constructor/destructor of TMyObject.
I cannot give advice on when to create and free these instances as I have no idea how your threads are created and freed.
First of all, I am not sure that it is a good design to allow worker thread to disable controls. However, I am curious can I do it safely without synchronization with GUI?
The code in TDataSet looks like this:
procedure TDataSet.DisableControls;
begin
if FDisableCount = 0 then
begin
FDisableState := FState;
FEnableEvent := deDataSetChange;
end;
Inc(FDisableCount);
end;
So it looks safe to do. The situation would be different in case of EnableControls. But DisableControls seems to only increase lock counter and assigning event which is fired up during EnableControls.
What do you think?
It looks safe to do so, but things may go wrong because these flags are used in code that may be in the middle of being executed at the moment you call this method from your thread.
I would Synchronise the call to DisableControls, because you want your thread to start using this dataset only if no controls are using it.
The call to EnableControls can be synchronised too, or you can post a message to the form using PostMessage. That way, the thread doesn't have to wait for the main thread.
But my gut feelings tells me that is may be better to not use the same dataset for the GUI and the thread at all.
Without having looked up the actual code: It might be safe, as long as you can be sure that the main thread currently does not access FDisableCount, FDisableState and FEnableEvent. There is the possibility of a race condition here.
I would still recommend that you call DisableControls from within the main thread.
I have never worked with threads before, and now I'm trying to create a thread with a query to check database status. The query is as follows:
select (*) as DBCount from v$datafile where status in 'OFFLINE';.
This query returns the total number of all the databases that are offline. Now I want to create a thread in Delphi that will execute this query in the background of my application when I run it and display the results on a label.
Multithreading is hard. You may be better off using a simple threading framework like AsyncCalls.
Following StackOverlow threads may give you more information on how to solve your problem:
Delphi - Threading frameworks
How Do I Choose Between the Various Ways to do Threading in Delphi?
Delphi thread that waits for data, processes it, then resumes waiting
This is fairly easy to do using AsyncCalls. Let's assume your non-threaded code looks like this (ignoring all error handling):
Query := 'select (*) as DBCount from...';
ExecuteSQL(SqlConnection,Query);
SqlResult := GetSqlResult(SqlConnection);
SqlRow := GetSqlRow(SqlResult);
MyLabel.Text := SqlRow[0];
...Go on to do other things...
Where the second line is blocking (waiting for the server to reply). Your new code would look like this:
uses AsyncCalls; //added to your existing uses statement
...
procedure DoesSomething();
var Thread: TAsyncCall; //your interface to AsyncCalls
procedure AsyncSqlCall(); //this is a LOCAL procedure
Query := 'select (*) as DBCount from...';
ExecuteSQL(SqlConnection,Query);
SqlResult := GetSqlResult(SqlConnection);
SqlRow := GetSqlRow(SqlResult);
EnterMainThread;
try
Assert(GetCurrentThreadId = MainThreadId);
MyLabel.Text := SqlRow[0];
finally
LeaveMainThread;
end;
begin //this begins proc DoSomething()
...
Thread := LocalAsyncCall(#AsyncSqlCall);
...Go on to do other things...
end;
All we've done is put the blocking SQL calls in a local proc and told AsyncCalls to execute it in another thread, while the main thread continues executing. The only tricky part was using the VCL, which is not thread-safe. So I had that line safely run in the main thread.
If at some point you need to be sure the Async thread has completed, you would execute this line to block the main thread till AsyncSqlCall terminates:
Thread.sync;
The really nice thing here is that AsyncCalls handles all the stuff about creating a thread pool, creating threads, etc. Though not shown in this example, you can pass variables to your thread, and return a value. You don't have to use a local proc, but doing so gives it access to all local vars. You could make all this global, and then launch the Async thread in one routine, and test for its completion in another.
Restrictions:
Your Async thread must not touch (read or write) anything but its own variables, and your main thread must not touch them while the Async thread is running. YOU must code it that way. Nothing will stop you from creating total chaos. In the above example, your main thread must not touch Query, SqlConnection, SqlResult, and SqlRow. If any part of your code used one of those vars before the Thread.sync call, your code would work -- but throw exceptions in weird places you never expected. So keep it simple.
Your Async thread must not use the VCL. The sample above shows one of several ways to safely get around this limitation.
Finally:
AsyncCalls is not a full Multi-Threading framework. It's just a way of calling procs & functions asynchronously (i.e. without waiting). Don't try to push it too far -- by which I mean, don't try to make it the basis of a fully multitasking program.
In Delphi there is TThread class. You can create such thread using simple wizard from Delphi IDE (in Turbo Delphi: File->New->Delphi Projects->Delphi Files->Thread Obcjet). In its constructor create connection to database, and in Execute method you can create loop that query database, update some global variable (NOT declared as threadvar) and sleep some time.
Here you can find a discussion about using threads on DataBase.
Simple Thread Sample Delphi
There are some code that can be usefull for you.
Regards.
A certain form in our application displays a graphical view of a model. The user can, amongst loads of other stuff, initiate a transformation of the model that can take quite some time. This transformation sometimes proceeds without any user interaction, at other times frequent user input is necessary. While it lasts the UI should be disabled (just showing a progress dialog) unless user input is needed.
Possible Approaches:
Ignore the issue, just put the transformation code in a procedure and call that. Bad because the app seems hung in cases where the transformation needs some time but requires no user input.
Sprinkle the code with callbacks: This is obtrusive - you’d have to put a lot of these calls in the transformation code - as well as unpredictable - you could never be sure that you’d found the right spots.
Sprinkle the code with Application.ProcessMessages: Same problems as with callbacks. Additionally you get all the issues with ProcessMessages.
Use a thread: This relieves us from the “obtrusive and unpredictable” part of 2. and 3. However it is a lot of work because of the “marshalling” that is needed for the user input - call Synchronize, put any needed parameters in tailor-made records etc. It’s also a nightmare to debug and prone to errors.
//EDIT: Our current solution is a thread. However it's a pain in the a** because of the user input. And there can be a lot of input code in a lot of routines. This gives me a feeling that a thread is not the right solution.
I'm going to embarass myself and post an outline of the unholy mix of GUI and work code that I've produced:
type
// Helper type to get the parameters into the Synchronize'd routine:
PGetSomeUserInputInfo = ^TGetSomeUserInputInfo;
TGetSomeUserInputInfo = record
FMyModelForm: TMyModelForm;
FModel: TMyModel;
// lots of in- and output parameters
FResult: Boolean;
end;
{ TMyThread }
function TMyThread.GetSomeUserInput(AMyModelForm: TMyModelForm;
AModel: TMyModel; (* the same parameters as in TGetSomeUserInputInfo *)): Boolean;
var
GSUII: TGetSomeUserInputInfo;
begin
GSUII.FMyModelForm := AMyModelForm;
GSUII.FModel := AModel;
// Set the input parameters in GSUII
FpCallbackParams := #GSUII; // FpCallbackParams is a Pointer field in TMyThread
Synchronize(DelegateGetSomeUserInput);
// Read the output parameters from GSUII
Result := GSUII.FResult;
end;
procedure TMyThread.DelegateGetSomeUserInput;
begin
with PGetSomeUserInputInfo(FpCallbackParams)^ do
FResult := FMyModelForm.DoGetSomeUserInput(FModel, (* the params go here *));
end;
{ TMyModelForm }
function TMyModelForm.DoGetSomeUserInput(Sender: TMyModel; (* and here *)): Boolean;
begin
// Show the dialog
end;
function TMyModelForm.GetSomeUserInput(Sender: TMyModel; (* the params again *)): Boolean;
begin
// The input can be necessary in different situations - some within a thread, some not.
if Assigned(FMyThread) then
Result := FMyThread.GetSomeUserInput(Self, Sender, (* the params *))
else
Result := DoGetSomeUserInput(Sender, (* the params *));
end;
Do you have any comments?
I think as long as your long-running transformations require user interaction, you're not going to be truly happy with any answer you get. So let's back up for a moment: Why do you need to interrupt the transformation with requests for more information? Are these really questions you couldn't have anticipated before starting the transformation? Surely the users aren't too happy about the interruptions, either, right? They can't just set the transformation going and then go get a cup of coffee; they need to sit and watch the progress bar in case there's an issue. Ugh.
Maybe the issues the transformation encounters are things that could be "saved up" until the end. Does the transformation need to know the answers immediately, or could it finish everything else, and then just do some "fix-ups" afterward?
Definitely go for a threaded option (even after your edit, saying you find it complex). The solution that duffymo suggests is, in my opinion, very poor UI design (even though it's not explicitly about the appearance, it is about how the user interfaces with your application). Programs that do this are annoying, because you have no idea how long the task will take, when it will complete, etc. The only way this approach could be made better would be by stamping the results with the generation date/time, but even then you require the user to remember when they started the process.
Take the time/effort and make the application useful, informative and less frustrating for your end user.
For an optimal solution you will have to analyse your code anyway, and find all the places to check whether the user wants to cancel the long-running operation. This is true both for a simple procedure and a threaded solution - you want the action to finish after a few tenths of a second to have your program appear responsive to the user.
Now what I would do first is to create an interface (or abstract base class) with methods like:
IModelTransformationGUIAdapter = interface
function isCanceled: boolean;
procedure setProgress(AStep: integer; AProgress, AProgressMax: integer);
procedure getUserInput1(...);
....
end;
and change the procedure to have a parameter of this interface or class:
procedure MyTransformation(AGuiAdapter: IModelTransformationGUIAdapter);
Now you are prepared to implement things in a background thread or directly in the main GUI thread, the transformation code itself will not need to be changed, once you have added code to update the progress and check for a cancel request. You only implement the interface in different ways.
I would definitely go without a worker thread, especially if you want to disable the GUI anyway. To make use of multiple processor cores you can always find parts of the transformation process that are relatively separated and process them in their own worker threads. This will give you much better throughput than a single worker thread, and it is easy to accomplish using AsyncCalls. Just start as many of them in parallel as you have processor cores.
Edit:
IMO this answer by Rob Kennedy is the most insightful yet, as it does not focus on the details of the implementation, but on the best experience for the user. This is surely the thing your program should be optimised for.
If there really is no way to either get all information before the transformation is started, or to run it and patch some things up later, then you still have the opportunity to make the computer do more work so that the user has a better experience. I see from your various comments that the transformation process has a lot of points where the execution branches depending on user input. One example that comes to mind is a point where the user has to choose between two alternatives (like horizontal or vertical direction) - you could simply use AsyncCalls to initiate both transformations, and there are chances that the moment the user has chosen his alternative both results are already calculated, so you can simply present the next input dialog. This would better utilise multi-core machines. Maybe an idea to follow up on.
TThread is perfect and easy to use.
Develope and debug your slow function.
if it is ready, put the call into the tthread execute method.
Use the onThreadTerminate Event to find out the end of you function.
for user feedback use syncronize!
I think your folly is thinking of the transformation as a single task. If user input is required as part of the calculation and the input asked for depends on the caclulation up to that point, then I would refactor the single task into a number of tasks.
You can then run a task, ask for user input, run the next task, ask for more input, run the next task, etc.
If you model the process as a workflow, it should become clear what tasks, decisions and user input is required.
I would run each task in a background thread to keep the user interface interactive, but without all the marshaling issues.
Process asynchronously by sending a message to a queue and have the listener do the processing. The controller sends an ACK message to the user that says "We've received your request for processing. Please check back later for results." Give the user a mailbox or link to check back and see how things are progressing.
While I don't completely understand what your trying to do, what I can offer is my view on a possible solution. My understanding is that you have a series of n things to do, and along the way decisions on one could cause one or more different things to be added to the "transformation". If this is the case, then I would attempt to separate (as much as possible) the GUI and decisions from the actual work that needs to be done. When the user kicks off the "transformation" I would (not in a thread yet) loop through each of the necessary decisions but not performing any work...just asking the questions required to do the work and then pushing the step along with the parameters into a list.
When the last question is done, spawn your thread passing it the list of steps to run along with the parameters. The advantage of this method is you can show a progress bar of 1 of n items to give the user an idea of how long it might take when they come back after getting their coffee.
I'd certainly go with threads. Working out how a thread will interact with the user is often difficult, but the solution that has worked well for me is to not have the thread interact with the user, but have the user side GUI interact with the thread. This solves the problem of updating the GUI using synchronize, and gives the user more responsive activity.
So, to do this, I use various variables in the thread, accessed by Get/Set routines that use critical sections, to contain status information. For starters, I'd have a "Cancelled" property for the GUI to set to ask the thread to stop please. Then a "Status"property that indicates if the thread is waiting, busy or complete. You might have a "human readable" status to indicate what is happening, or a percentage complete.
To read all this information, just use a timer on the form and update. I tend to have a "statusChanged" property too, which is set if one of the other items needs refreshing, which stops too much reading going on.
This has worked well for me in various apps, including one which displays the status of up to 8 threads in a list box with progress bars.
If you decide going with Threads, which I also find somewhat complex the way they are implemented in Delphi, I would recommend the OmniThreadLibrary by Primož Gabrijelčič or Gabr as he is known here at Stack Overflow.
It is the simplest to use threading library I know of. Gabr writes great stuff.
If you can split your transformation code into little chunks, then you can run that code when the processor is idle. Just create an event handler, hook it up to the Application.OnIdle event. As long as you make sure that each chunk of code is fairly short (the amount of time you want the application to be unresponsive...say 1/2 a second. The important thing is to set the done flag to false at the end of your handler :
procedure TMyForm .IdleEventHandler(Sender: TObject;
var Done: Boolean);
begin
{Do a small bit of work here}
Done := false;
end;
So for example if you have a loop, instead of using a for loop, use a while loop, make sure the scope of the loop variable is at the form level. Set it to zero before setting the onIdle event, then for example perform 10 loops per onidle hit until you hit the end of the loop.
Count := 0;
Application.OnIdle := IdleEventHandler;
...
...
procedure TMyForm .IdleEventHandler(Sender: TObject;
var Done: Boolean);
var
LocalCount : Integer;
begin
LocalCount := 0;
while (Count < MaxCount) and (Count < 10) do
begin
{Do a small bit of work here}
Inc(Count);
Inc(LocalCount);
end;
Done := false;
end;