I am developing an application with multithreading (RAD Studio XE5). At the start of the application I create a single thread that will live as long as the main form does.
I am able to dispatch messages from the thread to any form that has been created in my application, however I can't find a way to do the opposite, sending a message from the main VCL thread to the worker thread.
When creating the main form I create the worker thread and copy the handle in a public variable:
serverThread := TMyThread.Create(True, ServerPort + 1);
serverThreadHandle := serverThread.Handle; // SAVE HANDLE
serverThread.Start;
then (from a different form FrmSender) I dispatch a message to the thread:
PostMessage(uMain.serverThreadHandle, UM_LOC_VCLMSG, UM_LOC_VCLMSG, Integer(PStrListVar));
This is the thread's Execute procedure:
procedure TMyThread.Execute;
var
(..)
vclMSG : TMsg;
str1, str2 : string;
(..)
begin
while not(Terminated) do
begin
Sleep(10);
if Assigned(FrmSender) then
if FrmSender.HandleAllocated then
if PeekMessage(vclMSG, FrmSender.Handle, 0, 0, PM_NOREMOVE) then
begin
if vclMSG.message = UM_LOC_VCLMSG then
begin
try
pStrListVar := pStrList(vclMSG.lParam);
str1 := pStrListVar^.Strings[0];
str2 := pStrListVar^.Strings[1];
finally
Dispose(pStrListVar);
end;
end;
end;
(.. do other stuff ..)
end;
end;
However PeekMessage() never returns true as if it was never receiving any message. I've tried changing the parameters to PeekMessage():
PeekMessage(vclMSG, 0, 0, 0, PM_NOREMOVE);
But with no results.
Any ideas?
From MSDN PostMessage function documentation:
Places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.
To post a message in the message queue associated with a thread, use the PostThreadMessage function.
Thus, you should use PostThreadMessage:
Posts a message to the message queue of the specified thread. It returns without waiting for the thread to process the message.
Give special attention to the Remarks section. The recipient thread needs a message queue. Force the thread having one by following these steps:
Create an event object, then create the thread.
Use the WaitForSingleObject function to wait for the event to be set to the
signaled state before calling PostThreadMessage.
In the thread to which the message will be posted, call PeekMessage as shown here to force the system to create the message queue.
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE)
Set the event, to indicate that the
thread is ready to receive posted messages.
Then, when using PeekMessage, you pass a handle value of -1 to the function, as documented.
PeekMessage(vclMSG, FrmSender.Handle, 0, 0, PM_NOREMOVE)
The second argument means that you will only retrieve messages sent to the sender, FrmSender.Handle. But you sent the messages to the recipient, uMain.serverThreadHandle. This is one reason why PeekMessage can never return.
Accessing the VCL from the thread as you do is wrong. The form's handle is subject to VCL window re-creation and there is a clear race on HandleAllocated and Handle. So even if you needed to know FrmSender.Handle, it would be wrong to ask for it in the thread.
You are actually sending the message to a thread handle rather than a window handle. That means the message is never even sent, another reason why PeekMessage cannot return. Had you checked the return value when you called PostMessage you would have learnt that.
I'd use either PostThreadMessage, or post the message to a window allocated in the thread with a call to AllocateHWnd.
Once you do manage to actually send the message, your use of PM_NOREMOVE means that the message queue will never be emptied.
Your use of Sleep looks very dubious to me. Why not use GetMessage and so block until a message arrives. Anytime you see a call to Sleep, be very suspicious.
Your cast to Integer will lead to pointer truncation in a 64 bit build. The correct type to cast to is LPARAM.
I expect there are other mistakes, these are just the ones I could see in a quick 2 minute scan.
Related
I would like to ask few questions, let me explain things to you first and you can see the questions below this post. I created a multi threading app which reads and update data from a database. The threads communicates with the main thread using sendmessage. I am passing a pointer TRecord to sendmessage and dispose the pointer in the main thread. Below are code snippets that shows the structure of the process:
const WM_MY_MESSAGE = WM_USER + 0;
PTestPointerRecord : ^TTestPointerRecord;
TTestPointerRecord = record
i : integer;
end;
Here is the execute event of the extended TThread class. It will run continuously unless the thread was paused or terminated.
procedure TSampleThreadClass.Execute;
var
TestPointerRecord : PTestPointerRecord;
FConnection : TConnectionObject;
FQuery : TQueryObject;
begin
while not Terminated do
begin
New(PTestPointerRecord);
FConnection := TConnectionObject.Create(nil);
FQuery := TQueryObject.Create(nil);
try
FConnection.connectionstring := 'path';
FConnection.loginPrompt := False;
FConnection.open;
FQuery.connection := FConnection;
FQuery.close;
FQuery.sql.clear;
FQuery.sql.add('select column1, column2 from table');
FQuery.open;
PTestPointerRecord.i := 0;
SendMessage(frmMain.handle, WM_MY_MESSAGE, 0, integer(PTestPointerRecord));
finally
FQuery.close;
FConnection.disconnect;
FreeAndNil(FQuery);
FreeAndNil(FConnection);
sleep(250);
end;
end;
end;
Here is the event that receives the message from the thread.
procedure TfrmMain.message(msg : TMessage);
var
TestPointerRecord : PTestPointerRecord;
begin
TestPointerRecord := PTestPointerRecord(msg.lParam);
try
edit1.Text := inttostr(TestPointerRecord.i);
finally
Dispose(TestPointerRecord);
end;
end;
The app will be used as a service type application that will run continuously all time.
Questions:
1. Am I disposing the pointer properly?
2. When I checked my task manager while the app is running, I observed that under Processes Tab, I notice that Memory(Private working set) increases continuously. Is this fine?
Regards to all
I tried suggestion of David Heffernan about using a separate handle rather than using the main form's handle. This suggestion did not really solved the problem BUT thanks to David, it is worth using since he made a big point about problems that might occur when the main form's handle was used to received a message and the window was redrew or recreated.
Through deeper exploring of my codes through, debugging, trial and error. I found that the problem was reoccurring when I create the connection and query the database. Note, I am using ZeosLib to connect to the database, and seems that every time my thread loop, do the database operations, the working private memory keeps on increasing which is I'm not sure if Zeoslib is thread safe at all. So I switched to ADO and everything went well. The working private memory stays to a stable amount.
Thanks for all the help.
Given this scenario:
procedure TForm2.Button1Click(Sender: TObject);
var
Form: TForm;
begin
Form := TForm.Create(nil);
Form.OnClose := FormClosed;
Form.Show;
Sleep(200);
TThread.CreateAnonymousThread(
procedure
begin
TThread.Synchronize( nil,
procedure
begin
Form.Close;
MessageDlg('Testing', mtInformation, [mbok], 0);
end);
end).Start;
end;
procedure TForm2.FormClosed(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
end;
My MessageDlg call is not displayed (the result of this call is always mrCancel (2)).
After digging around, it's related to the OnClose event and setting the Action to caFree.
Changing Form.Close to Form.Free and removing the OnClose event entirely displays MessageDlg ok. Placing MessageDlg before the call to Form.Close works ok. Originally I thought scope of my Form variable might have caused the problem but declaring Formas a private field in TForm2 instance doesn't solve the problem.
My aim was to display a splash form, execute my thread, then through call backs of said thread, close the Splash form and display dialog where appropriate to the user.
For clarity, why does this occur?
What is happening is that the dialog's owning window is the form that is being closed. When the dialog starts its modal message loop, the form is released and takes down its owned windows with it. Including the dialog.
Test this out, to give you more confidence that what I state above is correct, by replacing the call to show the dialog first with
MessageBox(0, ...);
and then with
MessageBox(Form.Handle, ...);
That is, be explicit about the dialog's owner.
The first version, with no owner, will show the dialog. The second won't because it replicates the scenario in your code.
The Windows runtime requires that the messages for a visual window be processed by a message loop running in the same thread that creates that window.
The Windows API's also enforce rules about what operations can be performed on a window from a thread other than that in which the window was created. i.e. very little indeed, other than sending or posting messages to it.
With that information in mind, we can explain what is occurring in your case.
The Form.Close method ultimately closes a form by posting it a message (CM_RELEASE). But in your implementation the message loop responsible for responding to that message - the application main message loop - is blocked as a result of the fact that the message is posted from within a Synchronize() method.
i.e. your Synchronize()d method posts the message to close the form, but that message cannot and will not be processed by that forms window until your Synchronize()d method has completed, and that will not occur until the user has responded to the message box you are presenting in that method.
I hope that helps you understand what is going on in your code.
I have a project for a windows service which starts a thread to do some job, this part has been working for a long time, so not part of the problem. What I am trying to do is when this job starts and ends, it should start another thread (EventMessenger that inherited TThread) to send emails with a notification about the job has started and ended. I know you can not have nested threads, but i think it should ok to start one thread from another, then it will just belong to the main process. I create the thread in suspended mode, but i am uncertain whether it is ok to call assign for objects on the thread object while it is suspended.
EventMessenger := TEventMessenger.Create(true); // true = start suspended
EventMessenger.StatusCode := AStatusCode;
EventMessenger.Receiver.Assign(Receiver);
EventMessenger.MessageOptions.Assign(MessageOptions);
EventMessenger.MessageDetails := AMessage;
EventMessenger.FreeOnTerminate := true;
EventMessenger.Resume;
The Execute for TEventMessenger sends a mail using Indy TIdSmtp, here is a part of the code
try
self.FMessage.From.Address := ASender;
self.FMessage.Recipients.EMailAddresses := AReceiver;
self.FMessage.Subject := ASubject;
self.FMessage.Body.Text := AMessage;
try
self.FSMTP.Connect;
self.FSMTP.Send(self.FMessage);
except
on E:EIdException do
begin
CurrentEurekaLogOptions.ExceptionDialogOptions := []; // Don't show dialog box
StandardEurekaNotify(E, ExceptAddr()); // Save exception to file
end;
end;
finally
if self.FSMTP.Connected then
self.FSMTP.Disconnect;
end;
The first time i start the thread EventMessenger it works fine and sends an email about the job has started. However when it starts the EventMessenger again to send a mail about the job has stopped, i got a stack overflow in ntdll. I wonder if the assign in suspended mode can mess up the stack or whether there is some problem in indy; read that it could case problem if exceptions where not masked when mixing managed/unmanaged code, not sure whether this has anything to do with it. Note: I'm not using the default Indy in Delphi 2009, as it has several bugs, I'm running with Indy10 code downloaded from their repository in January.
:779e010f ntdll.KiUserExceptionDispatcher + 0xf
:77a2878b ; ntdll.dll
:779e010f ntdll.KiUserExceptionDispatcher + 0xf
:77a2878b ; ntdll.dll
:779e010f ntdll.KiUserExceptionDispatcher + 0xf
:77a2878b ; ntdll.dll
Any one got a idea what the actually problem is that causes the stack overflow or how i can catch the exception? I have wrapped the indy send in try/except, but i guess that only works for main process not threads, so I also added a try/except around the code in the EventMesssenger.Execute which calls HandleException that I have implemented like the following code, however it service crashes with AV without entering the ExceptionHandler.
procedure TEventMessenger.DoHandleException;
begin
if FException is Exception then
begin
CurrentEurekaLogOptions.ExceptionDialogOptions := []; // Don't show dialog box
StandardEurekaNotify(FException, ExceptAddr()); // Save exception to file
end;
end;
procedure TEventMessenger.HandleException;
begin
FException := Exception(ExceptObject);
try
if not (FException is EAbort) then
Synchronize(DoHandleException);
finally
FException := nil;
end;
end;
To answer your question - Assign() will work just fine while the thread is suspended. You are not touching the stack, as Assign() is a method of TPersistent, and Delphi objects exist on the heap, not the stack.
A stack overflow usually means that you encountered a recursive function call that never ended. Run the code in the debugger and look at the call stack when the overflow occurs, that will help you diagnose which function is getting stuck in a recursive loop.
Found my answer here, seems it had to do with hard-coded breakpoint microsoft had forgot to remove.
Unhandled Exception in Rad Studio Debugger Thread
I'm not a Delphi expert, and I have only a basic understanding of the flow of messages and the handling of events and callbacks. I'm trying to debug an application in D7 that need to combine the foreground procedure (initiated by a button click) with message reception and processing that occurs in the background (handled by a component). They both work properly independently, but when I combine them in one procedure, the message reception doesn't work.
The existing application already has functioning procedures to send a message on a button click, and it can receive a message while running and not processing any buttons.
The normal message reception is handled by a component, which calls my handler (OnInput) as an event. My handler puts the message in a ListBox.
I am trying to write a procedure that sends a message, and waits for a response, in a loop. (pseudocode):
for N := 0 to nsequence do begin
prevcount := ListBox1.items.count;
SendMessage(mymessage); // request the response
sleep(500); // allow time for response to arrive
for 0 to timeout do begin
sleep(100);
application.processmessages; {allow processing to handle incoming message}
if ListBox1.items.count > prevcount then break; {has the message arrived?}
end;
if ListBox1.items.count = prevcount then exit: {timeout -- fail}
end;
I think this should be able to be accomplished without threads, but the messages are never received. It always times out.
Are component event handlers able to be called from application.processmessages? The input message works correctly when the application is running and idle, but does not when it is executing a procedure. What else is required beyond a call to application.processmessages to cause the application to process messages and call the related procedures to handle them?
To trace the incoming message, the path starts with a callback from Windows MMSystem. When the MIDI Input port is opened, the callback is set to point to a handler: procedure midiHandler
In midiHandler, the event is put into a circular buffer: CircbufPutEvent( thisBuffer, #thisEvent).
Then a message is posted back to the application: PostMessage(thisCtlInfo^.hWindow, mim_Data, 0, 0)
That message is handled by: procedure TMidiInput.MidiInput( var Message: TMessage );
Within that procedure there is a call to: FOnMIDIInput(Self);
These events are defined in the component's interface as:
{ Events }
FOnMIDIInput: TNotifyEvent; { MIDI Input arrived }
under Published, we have:
{ Events }
property OnMidiInput: TNotifyEvent read FOnMidiInput write FOnMidiInput;
property OnOverflow: TNotifyEvent read FOnOverflow write FOnOverflow;
In the Object Inspector, the OnMidiInput event is linked to the procedure MIDIInput1MidiInput;
The procedure MIDIInput1MidiInput first calls GetMidiEvent:
with (Sender As TMidiInput) do
begin
while (MessageCount > 0) do
begin
{ Get the event as an object }
thisEvent := GetMidiEvent;
GetMidiEvent reads the message out of the circular buffer. The MIDIInput1MidiInput procedure does some checking and validating, and ultimately stores the message in ListBox1.
PS - the input component has a property that returns the count of queued messages in the circular buffer. I check it when the waiting loop times out, and it reports 0 messages. So the callback is apparently not getting to the midiHandler procedure.
Thanks to Jay's comments, I started digging deeper into what gets inhibited when a procedure is called.
To simplify my pseudo-code, I didn't include the fact that there are two sequential calls to the SendMessage procedure - one to set a parameter, and one to request the data in a reply. I didn't think there was an interaction between the output and input components because they are separate.
But I didn't realize that the sending component could interact with itself. Looking through the SendMessage code, I found it sends itself a message when done sending, which re-enables it to accept another message. The second message (the request for response) wasn't getting sent because the sending procedure didn't get re-enabled.
Putting an application.processmessages call between the two calls to the SendMessage procedure seems to have fixed this problem.
i created a class of TThread to do some socket operations, the thing is, the code doesnt work unless i add MessageBox to it, sockets wont work unless i put a MessageBox call before it
Sleep(2000); //Waiting for the Socket to Come to the Array
// Messagebox(0, '', '', 0); { Wont work unless this line is Uncommented }
if Server.ClientList[Handle] <> nil then
begin
if (Server.ClientList[Handle].Connected) and (AppSocket.Connected) do
begin
// Send Data on Socket
// Relay Data between Server.ClientList[Handle] and AppSocket;
end;
Assuming you are using non-blocking sockets, then your thread needs a running message queue and processing loop. That is why calling MessageBox() works - it is a modal dialog that pumps the calling thread's message queue internally. Your thread needs to call PeekMessage() or GetMessage() in a loop for the lifetime of the connection(s). Your loop can use MsgWaitForMultipleObjects() to detect when the message queue has something to process, if your thread has other things it needs to do.
Try to replace Messagebox() with Application.ProcessMessages and see what happens.