Multithreaded (TThread) Delphi application will not terminate - delphi

I have written an application (using Delphi 2009) that allows a user to select a series of queries which can be run across a number of different systems. In order to allow queries to be run concurrently, each query is run in its own thread, using a TADOQuery object. This all works fine.
The problem that I have is when I try to close the application when a query is still running (and therefore a separate thread is active). When I create each thread, I record the thread's THandle in an array. When I try to close the application, if any threads are still running, I retrieve the thread's handle and pass it to TerminateThread, which should theoretically terminate the thread and allow the application to close. However, this doesn't happen. The main form's onClose event is triggered and it looks like the application is closing, but the process remains active and my Delphi interface appears as though the application is still running (i.e. "Run" button greyed out, debug view active etc.). I don't get control back to Delphi until I manually end the process (either Ctrl-F2 in Delphi or via Task Manager).
I am using TerminateThread because the query can take a long time to run (a few minutes in cases where we're dealing with a million or so records, which in the end user environment is perfectly possible) and while it is running, unless I'm mistaken, the thread won't be able to check the Terminated property and therefore won't be able to end itself if this were set to True until the query had returned, so I can't terminate the thread in the usual way (i.e. by checking the Terminated property). It may be the case that the user wants to exit the application while a large query is running, and in that case, I need the application to immediately end (i.e. all running threads immediately terminate) rather than forcing them to wait until all queries have finished running, so TerminateThread would be ideal but it isn't actually terminating the thread!
Can anyone help out here? Does anyone know why TerminateThread doesn't work properly? Can anyone suggest anything to get the threads running large ADO queries to immediately terminate?

You should be able to cancel an ADO Query by hooking the OnFetchProgress event, and setting the Eventstatus variable to esCancel. This should cause your query to terminate and allow the thread to close gracefully without having to resort to using TerminateThread.

Instead of using threads with TADOQuery, maybe you should consider using the async options of ADO.
ADOQuery1.ExecuteOptions := [eoAsyncExecute, eoAsyncFetch, eoAsyncFetch];
Then when your application close, you can call :
ADOQuery1.cancel;

As you can read in the msdn using TerminateThread is dangerous.
TerminateThread is a dangerous
function that should only be used in
the most extreme cases. You should
call TerminateThread only if you know
exactly what the target thread is
doing, and you control all of the code
that the target thread could possibly
be running at the time of the
termination.
But it also is very effective in killing threads. Are you sure you are right in your conclusions? Maybe the thread is killed, but another thread is still running? Maybe your handles are not thread handles? Could you show us some code? Or even better: A small working example we could try for ourselves?

Related

TIdHTTPServer and 100% CPU usage

I use TIdHTTPServer in Delphi 11 to run a simple web server on a VPS.
It works great, except from time to time my app will start to use 100% of the CPU and keep this way forever, and I can't identify what is causing this.
When this happens, the server is still active and replying to requests, but very slowly. The only way to fix this is to force close the application and open it again.
I don't have any code to show, as my code is just generic responses using the OnCommandGet event of the TIdHTTPServer. This event will handle GET parameters on the URL and return something in the AResponseInfo.ContentText.
I know this is difficult, but any ideas about what I should hunt for to fix this?
We use TIdHttpServer quite a lot and have no problems with it. We use it in Delphi 10.3-10.4.2, but it’s not the reason for the problem. Programs work a few months without restarting.
From our experience we can say that problem of such unexpected behavior can be (in order of probability):
Code is not threadsafe. Event OnCommandGet run not in a main thread, so all access to global object/resources/etc must be done thru some kind of synchronization mechanism (locks, TEvent, synchronize, mutex, semaphore or other). If code does not use synchronization – it can broke logic, throw exceptions or do some other unexpected actions (like high CPU usage).
Connections count go over the limit. TIdHttpServer has properties like ListenQueue and MaxConnections. Can be that you make more requests that the server can handle. In this case your new requests wait until they can be handled by your code and it can make some additional CPU usage. To diagnose this – try to increment some internal variable at the start of your event and decrement it at the end. Make some service request to return this variable and you will know if all work correctly. Other similar situation – connection does not close after using the inside event and stay in memory, then you can go over limits too. Try to workaround properties TIdHttpServer.KeepAlive := false and TIdHttpServer.ReuseSocket := rsFalse.
Memory leaks. Try to set variable ReportMemoryLeaksOnShutdown := true and start the application, make a few requests and close it. If you’ll see a message with leaks – then you do something wrong, try to handle these objects in the right way. In production these small leaks can take a lot of RAM and Windows will dump part of memory into a swap-file, so your new requests will take more time to be processed.
Without an example, we can't say more.

Waiting for applications to finish loading [duplicate]

I have an application which needs to run several other applications in chain. I am running them via ShellExecuteEx. The order of running each of the apps is very important cause they are dependant on each other. For example:
Start(App1);
If App1.IsRunning then
Start(App2);
If App2.IsRunning then
Start(App3);
.........................
If App(N-1).IsRunning then
Start(App(N));
Everything works fine but there is a one possible problem:
ShellExecuteEx starts the application, and return almost immediately. The problem might arise when for example App1 has started properly but has not finished some internal tasks, it is not yet ready to use. But ShellExecuteEx is already starting App2 which depends on the App1, and App2 won't start properly because it needs fully initialized App1.
Please note, that I don't want to wait for App(N-1) to finish and then start AppN.
I don't know if this is possible to solve with ShellExecuteEx, I've tried to use
SEInfo.fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_NOASYNC;
but without any effect.
After starting the AppN application I have a handle to the process. If I assume that the application is initialized after its main window is created (all of Apps have a window), can I somehow put a hook on its message queue and wait until WM_CREATE appears or maybe WM_ACTIVATE? In pressence of such message my Application would know that it can move on.
It's just an idea. However, I don't know how to put such hook. So if you could help me in this or you have a better idea that would be great:)
Also, the solution must work on Windows XP and above.
Thanks for your time.
Edited
#Cosmic Prund: I don't understand why did you delete your answer? I might try your idea...
You can probably achieve what you need by calling WaitForInputIdle() on each process handle returned by ShellExecute().
Waits until the specified process has finished processing its initial input and is waiting for user input with no input pending, or until the time-out interval has elapsed.
If your application has some custom initialization logic that doesn't run in UI thread then WaitForInputIdle might not help. In that case you need a mechanism to signal the previous app that you're done initializing.
For signaling you can use named pipes, sockets, some RPC mechanism or a simple file based lock.
You can always use IPC and Interpocess Synchronization to make your application communicate with (and wait for, if needed) each other, as long as you code both applications.

If terminating a hung thread is a good idea, how do I do it safely?

My Delphi program relies heavily on Outlook automation. Outlook versions prior to 2007-SP2 tend to get stuck in memory due to badly written addins and badly written Outlook code.
If Outlook is stuck, calling CreateOleObject('Outlook.Application') or GetActiveObject ... doesn't return and keeps my application hanging till Outlook.exe is closed in the task manager.
I've thought of a solution, but I'm unsure whether it's good practice or not.
I'd start Outlook with CreateOleObject in a separate thread, wait 10 seconds in my main thread and if Outlook hangs (CreateOleObject doesn't return), offer the user to kill the Outlook.exe process from my program.
But since I don't want to force the user to kill the Outlook.exe process, as an alternative I also need a way to kill the new thread in my program which keeps hanging now.
Is this good practice?
How can I terminate a hanging thread in Delphi without leaking memory?
Windows has a TerminateThread function, but as you can see from the remarks, it's not generally a good idea to use it. A safer approach would be to have a secondary application that interacts with Outlook, and you could then kill that without affecting your own application's stability. TerminateProcess would work, but if you wanted to be a little friendlier to the system Dr. Dobbs has an article on a possibly safer approach using ExitProcess.
If the hang is consistent and always either happens or doesn't happen, you can just call CreateOleObject in the app and exit, then call it again from your own. If it's inconsistent the secondary application could be a more complete wrapper, and all the interactions would go through it.
And additionally, you can use thread's Context's eip register.
You can find a sample at;
http://www.tugrulhelvaci.com/?p=568

Delphi Thread freeze

I coding a service application that have two threads.
First thread, show a form with label.
Second thread, query ADO.
First thread always freezing with Hourglass cursor and no label caption.
Please help.
If you're trying to show a form from within a thread that is not the main thread, then you will run into strange things like this. The most notable of which is that if the form and label are created in the non-main thread, then you don't have a message loop to process the messages. If the form was created in the main thread, but you're attempting to show it from the non-main thread, then it is likely a dead lock due to how Windows deals with messages and threads.
When a window handle is created it is tied to the thread on which it was created. This means that Windows will ensure that any messages sent to that handle are processed on that thread.
I would strongly suggest you read up on how window messages, message queues, and handles all interact and function in a multi-threaded environment. If not done correctly, you are assured of some very odd and possibly unpredictable behavior.
I would call your condition either a Race, a Deadlock, or some other kind of error like that. As Allen says, if the background thread makes ANY direct access to the VCL controls, without using TThread.Synchronize(myMethod) to invoke the myMethod that touches your VCL foreground, then this alone would cause your trouble.
Post more information, including a sample of your code please.

Overlapped serial port and Blue Screen of Death

I created a class that handles serial port asynchronously. I use it to communicate with a modem. I have no idea why, but sometimes, when I close my application, I get the Blue Screen and my computer restarts. I logged my code step by step, but when the BSOD appeared, and my computer restarted, the file into which I was logging data contained only white spaces. Therefore I have no idea, what the reason of the BSOD could be.
I looked through my code carefully and I found several possible reasons of the problem (I was looking for all that could lead to accessing unallocated memory and causing AV exceptions).
When I rethought the idea of asynchronous operations, a few things came to my mind. Please verify whether these are right:
1) WaitCommEvent() takes a pointer to the overlapped structure. Therefore, if I call WaitCommEvent() inside a function and then leave the function, the overlapped structure cannot be a local variable, right? The event mask variable and event handle too, right?
2) ReadFile() and WriteFile() also take references or pointers to variables. Therefore all these variables have to be accessible until the overlapped read or write operations finish, right?
3) I call WaitCommEvent() only once and check for its result in a loop, in the mean time doing other things. Because I have no idea how to terminate asynchronous operations (is it possible?), when I destroy my class that keeps a handle to a serial port, I first close the handle, and then wait for the event in the overlapped structure that was used when calling the WaitCommEvent() function. I do this to be sure that the thread that waits asynchronously for a comm event does not access any fields of my class which is destroyed. Is it a good idea or is it stupid?
try
CloseHandle(FSerialPortHandle);
if Assigned(FWaitCommEvent) then
FWaitCommEvent.WaitFor(INFINITE);
finally
FSerialPortHandle := INVALID_HANDLE_VALUE;
FreeAndNil(FWaitCommEvent);
end;
Before I noticed all these, most of the variables mentioned in point one and two were local variables of the functions that called the three methods above. Could it be the reason of the BSOD or should I look for some other mistakes in my code?
When I corrected the code, the BSOD stopped occuring, but It might be a coincidence. How do you think?
Any ideas will be appreciated. Thanks in advance.
I read the CancelIo() function documentation and it states that this method cancells all I/O operations issued by the calling thread. Is it OK to wait for the FWaitCommEvent after calling CancelIo() if I know that WaitCommEvent() was issued by a different thread than the one that calls CancelIo()?
if Assigned(FWaitCommEvent) and CancelIo(FSerialPortHandle) then
begin
FWaitCommEvent.WaitFor(INFINITE);
FreeAndNil(FWaitCommEvent);
end;
I checked what happens in such case and the thread calling this piece of code didn't get deadlocked even though it did not issue WaitCommEvent(). I tested in on Windows 7 (if it matters). May I leave the code as is or is it dangerous? Maybe I misunderstood the documentation and this is the reason of my question. I apologize for asking so many questions, but I really need to be sure about that.
Thanks.
An application running as a standard user should never be able to cause a bug check (a.k.a. BSOD). (And an application running as an Administrator should have to go well out of its way to do so.) Either you ran into a driver bug or you have bad hardware.
By default, Windows is configured to save a minidump in %SystemRoot%\minidump whenever a bug check occurs. You may be able to determine more information about the crash by loading the minidump file in WinDbg, configuring WinDbg to use the Microsoft public symbol store, and running the !analyze -v command in WinDbg. At the very least, this should identify what driver is probably at fault (though I would guess it's your modem driver).
Yes, you do need to keep the TOverlapped structure available for the duration of the overlapped operation. You're going to call GetOverlappedResult at some point, and GetOverlappedResult says it should receive a pointer to a structure that was used when starting the overlapped operation. The event mask and handle can be stored in local variables if you want; you're going to have a copy of them in the TOverlapped structure anyway.
Yes, the buffers that ReadFile and WriteFile use must remain valid. They do not make their own local copies to use internally. The documentation for ReadFile even says so:
This buffer must remain valid for the duration of the read operation. The caller must not use this buffer until the read operation is completed.
If you weren't obeying that rule, then you were likely reading into unreserved stack space, which could easily cause all sorts of unexpected behavior.
To cancel an overlapped I/O operation, use CancelIo. It's essential that you not free the memory of your TOverlapped record until you're sure the associated operation has terminated. Likewise for the buffer you're reading or writing. CancelIo does not cancel the operation immediately, so your buffers might still be in use even after you call it.

Resources