There is a thread class:

TNewThread = class(TThread) private procedure Parser_auto_info(var MLQuery: TADOQuery; MTable: TADOTable); protected procedure Execute; override; public MPersent, StartRegion, EndRegion, idHandle: integer; StartThread: boolean; end; 

And three instances of these are declared in the public section of the form variables:

 var NewThread, NewThread2, NewThread3: TNewThread; 

The start of the stream goes like this:

  // поток 1 NewThread := TNewThread.Create; with NewThread do begin FreeOnTerminate:=true; Priority:=tpLower; Resume; idHandle:=1; StartRegion:=pos1Region; //1; EndRegion:=54; StartThread:=true; end; 

I put the following code on the Close event of the form:

  if NewThread.StartThread then try TerminateThread(NewThread.Handle, 0); finally NewThread.Free; end; 

He throws a memory error. I tried to close the stream with the form:

  if not Assigned(NewThread) then NewThread.Terminate; FreeAndNil(NewThread); 

I tried to register in the destroy event of the form:

 NewThread.Free; 

But this does not help either. Errors are persistent, due to the fact that the thread (s) closes incorrectly. How to beat this error? Immediately I say that the stream is still working with the database, outputting data to the form (counters and download progress).

  • Where is the constructor and destructor? Where is the initialization of ADO? - Interface Unknown

2 answers 2

First, the use of ADO in streams provides for the use of its TADOConnection in each of the streams, so it is already incorrect to transmit ADOQuery from the form. Secondly, because ADO is COM, you need to call CoInitialize / CoUnitialize :

 procedure TMyThread.Execute; begin CoInitialize(nil); try try // Создание соединения или // прямо при создании TADOQuery // указать для нее ConnectionString except end; finally CoUnInitialize; end; end; 

see Multithreaded Delphi Database Queries

Thirdly, with regard to correct completion and release, it is enough to call NewThread.Terminate from the triggering thread (by a button, for example, or by closing a form). Next, the thread should terminate itself by checking the Terminated (interrupt your cycle). The presence of an additional variable is not necessary, you do not need to call Free and so TThread , TThread is in charge of the TThread , you explicitly specified FreeOnTerminate:=True .

  • Impeccable answer. About ADO, I also tried to clarify. I wanted to understand how the author initializes ADO. In the answer it is described proactively. +1 - Interface Unknown
  • Thanks for the really helpful answer! And yet, judging by the code that resulted in the link, there is still no ADOConnection created in the stream class, it loads external data from the existing connector. The only difference from my version is that the table in the code creates an internal one there, and it is used, having previously connected, the connector component. For the rest I did the same. - IntegralAL
  • type TCalcThread = class (TThread) private procedure RefreshCount; protected procedure Execute; override; public ConnStr: widestring; SQLString: widestring; ListBox: TListBox; Priority: TThreadPriority; TicksLabel: TLabel; Ticks: Cardinal; end; - IntegralAL
  • Note the commented lines. This article is about how to do and what you can not pass, in particular the "connector". // MUST USE OWN CONNECTION. TADOConnection is created inside TADOQuery if the connection string is specified - ConnStr, i.e. inside the stream. - Yura Ivanov
  • Yeah thanks. Another question, now is creating a dummy in the execute method of the stream without a loop. CoInitialize (nil); CoUninitialize (); It gives a memory error. Connected ActiveX module. What can cause such an error? - IntegralAL

Do not use Resume . This method, starting with XE, in my opinion, is depressed. Resume use Start . But only if the thread is created Suspended, i.e. an overloaded constructor is called with the CreateSuspended := true parameter CreateSuspended := true

 MyThread := TMyThread.Create(True); ... MyThread.Start; 

Do not forcefully stop an already running thread. This will cause a resource leak (memory leaks). The flow can only be influenced by , for example, notifying it that you want to interrupt it. The flow will end when the last statement in the Execute block is executed or the value of Terminated returns to True (I do not consider cases of pulling out of the socket or de-energizing the neighborhood).

Options NewThread.Free , NewThread = nil will not bring a good result. Such methods can forcibly stop the flow and cause resource locks or memory leaks.

In order for the stream to complete correctly, you need to do the following:

  • Wait until it is completed (trivial, but true)
  • Tell the stream that you are asking it to end.

I will describe the second method in more detail: This is a cooperative method of the main and subsidiary threads. You must call the terminate flow method. And inside Execute program the verification of the Terminated property. After that, Execute will periodically check for the presence of the set Termnated property and when it appears, the thread will stop and if FreeOnTerminate := true correctly release all resources (clean up objects, release locks, etc.)

  • Completely incorrect answer. I think I can’t take part in the discussion anymore. - Interface Unknown
  • What exactly do you dislike? What I do not declare and do not programmatically create ADO components, but already use those that already lie on the form of my project or that it is possible to terminate them through a terminate about the interruption of threads? Better then tell us how to classify the stream that communicates with the form (passes the load indicator) as a synchronous or asynchronous stream? - IntegralAL
  • And by the way, using the Start method generally causes an error for me, unlike Resume. He writes: "Cannot call start on a running or suspended thread. I use XE7. Did you really work very well with threads on this delphi? - IntegralAL
  • @IntegralAL Well, of course there will be an error. Because the CreateSuspended parameter is not passed to the CreateSuspended , which by default is False . If you call the constructor via NewThread:=TNewThread.Create(True); then calling the Start method does not cause an error. - Interface Unknown
  • 2
    Create a separate file as a key to stop the flow? What kind of nonsense? A boolean variable is enough (and it already exists - this is the property of Terminated). - Pavel Mayorov