Thursday, October 17, 2024

Extending the auxiliary program

Pretty keen - yes, my hobby keeps me busy
and if I talk to myself, what's the crime?

- Peter Hammill, "Last frame"

After a good night's sleep, my right brain came up with an interesting idea that extends yesterday's solution 1 of an external program to calculate correlations. What would happen if I had another calculation that required heavy processing? Would I create a new external program with its dedicated messages?

No: all I need to do is create a general, auxiliary, program to which is passed a string of parameters, where the first parameter is the function number within the auxiliary program to be executed. When that function completes, it sends a message back to the main program, where one parameter is the function number and the second parameter is the data instance number. This reminds me vaguely of the old DOS Int 21h interface.

As this auxiliary program is going to support a variety of calculations, it makes sense to have certain portions global to the program - the initialisation of the database along with the NewInstance and CloseInstance function/procedure. Then all the specific correlation code can go into one procedure with its local variables.

As I mentioned yesterday, I am using the InterBase components; this makes initialising the database easier especially as I am writing a text-only unit. One major difference between the InterBase components and the dbExpress set is that the first set uses transactions. I discovered in a painful manner yesterday that in order for a query to insert or update data in the database, the transaction has to be committed, otherwise nothing happens. Not only that, the transaction has to be set as non-active after the commit so that it can be reused. This flag setting seems to be required after every database action, regardless of whether its an insertion or a selection. This has tripped me up several times, and I'm not sure if I am yet capable of writing a sequence of SQL commands without getting an error message about the transaction.

As this blog's epigraph puts, "yes, my hobby keeps me busy". I enjoy programming - or at least, defining what has to be programmed. As code rarely works the way it is intended first time, I have to debug a certain amount/great deal, and this can be tedious.

Internal links
[1] 1839



This day in history:

Blog #Date TitleTags
29417/10/2010Sweet and sour chickenCooking, Slow cooker
29517/10/2010Project Management courseMBA, Project management
41717/10/2011Getting ready for the KindleKindle, E-book
98317/10/2016Who's watching who?Grandfather
134917/10/2020Completing the story of porting an application to Windows 10/Delphi 10.2Delphi, Unicode

Wednesday, October 16, 2024

Removing the thread code and finding a different solution

After several hours of testing, I came to the reluctant conclusion that nothing works in the program when this type of thread is executing - somewhat negating the whole point of having a thread! I've restored the program to how it was on Saturday night: the interface form calculates the correlations and saves the data in an instance of the temp table. A secondary form is called to display the data.

I've been experimenting on a separate copy of the program units, and it appears that something connected with the database code in the thread is causing the problem. I'm using completely different database components and not accessing any units whatsoever but there the problem still exists.

So, I wondered, what else can I do? An old solution popped into my head: execute a separate program to do the work. This program can be passed whatever parameters are necessary, and can send a message to the main program that data is waiting to be displayed. But it's not always necessary to execute a separate program: if there aren't that many data points to be calculated then it's quicker to do this within the existing program. I determined that - on my computer - 2500 records is approximately the tipping point.

The first part of the code - entering into the temp table the records that will act as the input for the correlation code - remains in the interface unit. Instead of having to issue a separate query in order to determine how many tuples have been inserted, I simply store the return value of the ExecSQL function. Almost always I ignore the return value, which is the number of tuples affected by the query. In this case, the number of tuples will be the number of tuples inserted which is the total number of examinees. 

If this number is less than 2500 then the original code executes within the interface unit; at the end, the son form is created directly to display the data. Should there be more than 2500 tuples, then first a string is built with all the parameters that need to be passed, eg '21 15 12 01/01/22'. Then the external program is executed, receiving this string. It turns out that almost all of the thread code that I wrote could be transferred without change into the external program, including all the database code. In order to simplify matters for myself, I am using the InterBase components as opposed to the dbExpress components that I normally use. Again, this program does not include any module from the main program.

The final line in this program is 'sendmessage (hwnd_broadcast, RegisterWindowMessage ('Show correl'), rinstance, 0)'; this sends a message to every open program on the computer (because the program doesn't know who executed it) with a message number that is not necessarily constant; also using the RegisterWindowMessage technique means that the message number is known only to this pair of programs. I discussed1 this Windows technique way way back in 2009. The call arrives at the overridden DefaultMessage handler that calls the secondary form to display the data.

Finally, success.

Internal links
[1] 176



This day in history:

Blog #Date TitleTags
134816/10/2020PrioXRef 3 - insert without parametersProgramming
153816/10/2022Indexing blogsProgramming, Meta-blogging, Blog manager program
167816/10/2023The running graveCormoran Strike