Opening Multiple Queries in Threads

Discussion of open issues, suggestions and bugs regarding SDAC (SQL Server Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
garry
Posts: 7
Joined: Mon 02 Nov 2009 13:24
Location: India
Contact:

Opening Multiple Queries in Threads

Post by garry » Sun 11 Jul 2010 14:36

My requirement is to open multiple queries at the same time.

I tried with approach used in this post
http://www.devart.com/forums/viewtopic. ... ht=threads

I am attaching here the sample program i made with using this approach and master database...

Please create a new delphi project and use dfm and pas that I pasted below.

Before running update the connection info, then set connected := False at design time.

Then run the application.

If you choose "Opendatasets" in the radiogroup it workds, but choosing "Threads" it doesn't. Could you help me in identifying the problem?

Note: I need to use a single connection in my application, I cannot use one per thread.


DFM

=============

object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 360
ClientWidth = 850
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 88
Top = 24
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object RadioGroup2: TRadioGroup
Left = 120
Top = 96
Width = 201
Height = 105
Caption = 'Choose Method for executing queries'
ItemIndex = 0
Items.Strings = (
'Nothing'
'OpenDataSets'
'Threads')
TabOrder = 1
end
object MSConnection1: TMSConnection
Database = 'Master'
Username = 'sa'
Password = 'XXXXXX'
Server ='XXXXXXX'
Left = 40
Top = 104
end
object MSQuery1: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 432
Top = 8
end
object MSQuery2: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 432
Top = 64
end
object MSQuery3: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 432
Top = 128
end
object MSQuery4: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 432
Top = 192
end
object MSQuery5: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 432
Top = 256
end
object MSQuery6: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 496
Top = 8
end
object MSQuery7: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 496
Top = 64
end
object MSQuery8: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 496
Top = 128
end
object MSQuery9: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 496
Top = 192
end
object MSQuery10: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 496
Top = 256
end
object MSQuery11: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 552
Top = 8
end
object MSQuery12: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 552
Top = 64
end
object MSQuery13: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 552
Top = 128
end
object MSQuery14: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 552
Top = 192
end
object MSQuery15: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 552
Top = 256
end
object MSQuery16: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 616
Top = 8
end
object MSQuery17: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 616
Top = 64
end
object MSQuery18: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 616
Top = 128
end
object MSQuery19: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 616
Top = 192
end
object MSQuery20: TMSQuery
Connection = MSConnection1
SQL.Strings = (
'select * from sysprocesses')
Left = 616
Top = 256
end
end
=========PAS File==========
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, MemDS, DBAccess, MSAccess, StdCtrls, ExtCtrls;

type
TThreadDone = procedure(Sender: TObject;ThIndex :Integer) of object;

TForm1 = class(TForm)
Button1: TButton;
MSConnection1: TMSConnection;
MSQuery1: TMSQuery;
MSQuery2: TMSQuery;
MSQuery3: TMSQuery;
MSQuery4: TMSQuery;
MSQuery5: TMSQuery;
MSQuery6: TMSQuery;
MSQuery7: TMSQuery;
MSQuery8: TMSQuery;
MSQuery9: TMSQuery;
MSQuery10: TMSQuery;
MSQuery11: TMSQuery;
MSQuery12: TMSQuery;
MSQuery13: TMSQuery;
MSQuery14: TMSQuery;
MSQuery15: TMSQuery;
MSQuery16: TMSQuery;
MSQuery17: TMSQuery;
MSQuery18: TMSQuery;
MSQuery19: TMSQuery;
MSQuery20: TMSQuery;
RadioGroup2: TRadioGroup;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Procedure OpenQueriesInThread(Qrys : Array of TMSQuery);
Procedure ThreadExecuted(Sender: TObject;ThIndex :Integer);

end;
TQryThread= class(TThread)
private
{ Private declarations }
FThIndex : Integer;
FThreadDone : TThreadDone;
FQuery : TMSQuery;
FIsCompleted : Boolean;
Procedure DoOnTerminate(Sender: TObject);
protected
Constructor CreateIt(ThIndex:Integer;Qry : TMSQuery;ThreadDone : TThreadDone);
procedure Execute; override;
Property IsCompleted :Boolean read FIsCompleted write FIsCompleted;
end;


var
Form1: TForm1;
Thrds : Array of TQryThread;

implementation
uses ActiveX,mmsystem;
{$R *.dfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
st,en :Cardinal;
begin
Try

CoInitialize(nil); // <-- manually call CoInitialize()
MSConnection1.Connected := True;
MSQuery1.Close;
MSQuery2.Close;
MSQuery3.Close;
MSQuery4.Close;
MSQuery5.Close;
MSQuery6.Close;
MSQuery7.Close;
MSQuery8.Close;
MSQuery9.Close;
MSQuery10.Close;
MSQuery11.Close;
MSQuery12.Close;
MSQuery13.Close;
MSQuery14.Close;
MSQuery15.Close;
MSQuery16.Close;
MSQuery17.Close;
MSQuery18.Close;
MSQuery19.Close;
MSQuery20.Close;

st := timegettime;
if RadioGroup2.ItemIndex = 0 then
begin
MSQuery1.Open;
MSQuery2.Open;
MSQuery3.Open;
MSQuery4.Open;
MSQuery5.Open;
MSQuery6.Open;
MSQuery7.Open;
MSQuery8.Open;
MSQuery9.Open;
MSQuery10.Open;
MSQuery11.Open;
MSQuery12.Open;
MSQuery13.Open;
MSQuery14.Open;
MSQuery15.Open;
MSQuery16.Open;
MSQuery17.Open;
MSQuery18.Open;
MSQuery19.Open;
MSQuery20.Open;
end;
if RadioGroup2.ItemIndex = 1 then
begin
MsConnection1.OpenDatasets([
MSQuery1,
MSQuery2,
MSQuery3,
MSQuery4,
MSQuery5,
MSQuery6,
MSQuery7,
MSQuery8,
MSQuery9,
MSQuery10,
MSQuery11,
MSQuery12,
MSQuery13,
MSQuery14,
MSQuery15,
MSQuery16,
MSQuery17,
MSQuery18,
MSQuery19,
MSQuery20]);
end;
if RadioGroup2.ItemIndex = 2 then
begin
OpenQueriesInThread([
MSQuery1,
MSQuery2,
MSQuery3,
MSQuery4,
MSQuery5,
MSQuery6,
MSQuery7,
MSQuery8,
MSQuery9,
MSQuery10,
MSQuery11,
MSQuery12,
MSQuery13,
MSQuery14,
MSQuery15,
MSQuery16,
MSQuery17,
MSQuery18,
MSQuery19,
MSQuery20]);
end;




ShowMEssage('Done !! Total time taken '+IntTostr(timeGetTime - st));
Finally
MSConnection1.Connected := False;

CoUnInitialize; // <-- free memory
End;
end;

procedure TForm1.OpenQueriesInThread(Qrys: array of TMSQuery);
var
iThrd : Integer;
ThDone : array of TThreadDone;

Function IsAllThreadExecuted : Boolean;
var it : Integer;
begin
result := true;
for it := Low(Thrds) to High(Thrds) do
begin
if not Thrds[it].IsCompleted then
begin
result := false;
break;
end;
end;
end;

begin
SetLength(Thrds,0);
SetLength(Thrds,High(Qrys)+1);
SetLength(ThDone,0);
SetLength(ThDone,High(Qrys)+1);
for iThrd := Low(Thrds) to High(Thrds) do
begin
ThDone[iThrd] := ThreadExecuted;
Thrds[iThrd] := TQryThread.CreateIt(iThrd,Qrys[iThrd],ThDone[iThrd]);
end;
repeat
Application.ProcessMessages;
until IsAllThreadExecuted;
for iThrd := High(Thrds) downto Low(Thrds) do
begin
Freeandnil(Thrds[iThrd]);
end;
end;

procedure TForm1.ThreadExecuted(Sender: TObject; ThIndex: Integer);
begin
Thrds[ThIndex].IsCompleted := true;

end;

{ TQryThread }

constructor TQryThread.CreateIt(ThIndex: Integer; Qry: TMSQuery;
ThreadDone: TThreadDone);
begin
Create(True);
FThIndex :=ThIndex;
FThreadDone := ThreadDone;
FQuery := Qry;
FreeOnTerminate := false;
FIsCompleted := False;
OnTerminate := DoOnTerminate;
Priority := tpNormal;
Resume;

end;

procedure TQryThread.DoOnTerminate(Sender: TObject);
begin
FIsCompleted := True;
if Assigned(FThreadDone) then
FThreadDone(self,FThIndex);

end;

procedure TQryThread.Execute;
begin
inherited;
FQuery.Open;
end;

end.
=============

Challenger
Devart Team
Posts: 925
Joined: Thu 17 Nov 2005 10:53

Post by Challenger » Mon 12 Jul 2010 12:58

But you should use a seperate connection for each thread. Otherwise you may get unexpected errors.

Post Reply