Solved

Hand out TTables

Posted on 1998-03-07
9
209 Views
Last Modified: 2010-08-05
Hi,

I am going to write a ISAPI extension which is performing some database actions. The problem is that I dosn't want to create a new TTable for each request since that would slow down the requests to much. And one TTable would be too few since some request could be lengthy. What I was wondering was how to make it like each request asks for a TTable, and wait if it isn't some free. If there is an free the request will get it.
Is it something I have to remeber when doing this?
Hope somebody understand what I ment.

Thanks

With best regards
Christian Bøhn
0
Comment
Question by:chrb
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 3
9 Comments
 
LVL 5

Expert Comment

by:inter
ID: 1360234
Hi,

If I can understand, Say we have a N resources (TTables on our form-or you may prefer to create them dynamically-) For being clear lets say we have 4 tables for performing DB operations. Lets call these as Table1, Table2, Table3, Table4.  We do the following:

1 - On creation of the application store them in a list and mark their states:(lets say it is var TableList : TStringList;
..
  TableList := TStringList.Create;
  TableList.AddObject('Idle', Table1);
  TableList.AddObject('Idle', Table2);
  TableList.AddObject('Idle', Table3);
  TableList.AddObject('Idle', Table4);
..

2 - When a request is made check for them and return one of the idle tables:
function Form1.GetIdleTable:TTable;
var
  i : integer;
begin
  Result := nil; // assume not found
  for i:=0 to TableList.Count-1 do
    if TableList[i] = 'Idle' then
    begin
      Result := TTable(TableList.Objects[i]);
      TableList[i] := 'Busy';
      Break;
    end;
end;
3 - Write down a method so that sub tasks can release the table when finished their tasks
procedure Form1.ReleaseTable(T : TTable);
var
  i : integer;
begin
  for i:=0 to TableList.Count-1 do
    if TableList.Objects = Pointer(T)  then
    begin
      TableList[i] := 'Idle';
      Break;
    end;
end;
4 - On caller of the method in step 3, wait until an idle table returns
...
  MyTable := GetIdleTable;
  while MyTable = nil do MyTable := GetIdleTable;
  // now use MyTable for the querry
...
5 - After using a the table a process should release it as follows:
...
   // Assume we have done with MyTable obtained in step 4
  ReleaseTable(MyTable);
...

Is this ok?
Regards
Igor
0
 

Author Comment

by:chrb
ID: 1360235
I will take a look at it, but as far as I see it isn't thread safe. I forgot to meantion that this was going to be access by a lot of threads. But it shouldn't be hard to add some critical sections?

Chr
0
 
LVL 5

Expert Comment

by:inter
ID: 1360236
Hi,

You are surely right. Here is a critical section I wrote before. If you can, the threads and criticals section objects be in the same unit: so in your thread unit declare
...
implementation
Uses
   Sync;
var
  MyCs : TCriticalSection;
...
initialization
  MyCs := TCriticalSection.Create;
finalization
  MyCs.Free;
end.

THEN IN YOUR THREADS CODE DO:

procedure ThreadMain...
begin
...
   if NeedsProcessing then
   begin
     MyCs.Lock;
     MyTable := GetIdleTable;
     MyCs.UnLock;
   end;
...
   if FinishedProcessing then
   begin
     MyCs.Lock;
     ReleaseTable(MyTable);
     MyCs.Unlock;
  end;
..
end;

THIS IS THE CODE FOR SYNC IF YOU THERE RESPOND PLEASE

unit Synch;

interface
uses
  Windows;

type
  TCriticalSection = class(TObject)
  private
    GlobalCriticalSection : TRTLCriticalSection;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Lock;
    procedure UnLock;
  end;

  // By now only named mutexes are supported
  TMutex = class(TObject)
  private
    HMutex : THandle;    // This one is mutex handle
    HandleValid : boolean;
    FName  : string;     // This one is mutex name
  public
    constructor Create(AName : string);
    destructor Destroy; override;
    procedure Lock;
    procedure UnLock;
  end;

implementation
uses
  SysUtils;
constructor TCriticalSection.Create;
begin
  InitializeCriticalSection(GlobalCriticalSection);
end;

destructor TCriticalSection.Destroy;
begin
  DeleteCriticalSection(GlobalCriticalSection);
  inherited Destroy;
end;

procedure TCriticalSection.Lock;
begin
  EnterCriticalSection(GlobalCriticalSection);
end;

procedure TCriticalSection.UnLock;
begin
  LeaveCriticalSection(GlobalCriticalSection);
end;

constructor TMutex.Create(AName : string);
var
  Str : array[0..255] of char;
begin
  FName := AName;
  HandleValid := false;
  StrPCopy(Str, FName);
  HMutex := CreateMutex(
            nil,     // security NONE
            false,   // no initial owner
            Str);  // mutex name
  if (HMutex = NULL) then
  begin
  end;
end;

destructor TMutex.Destroy;
begin
  // Do nothing since mutexes automatically deleted
  inherited Destroy;
end;

procedure TMutex.Lock;
var
  dwWaitResult : DWORD;
begin
// wait for ovnership time out 0 by now
   dwWaitResult := WaitForSingleObject(HMutex, INFINITE);
   case dwWaitResult of
     WAIT_OBJECT_0  : HandleValid := true;//OK
     WAIT_TIMEOUT: ;
     WAIT_ABANDONED: ;
   end;
end;

procedure TMutex.UnLock;
begin
  if HandleValid then
  begin
    ReleaseMutex(HMutex);
    HandleValid := false;
  end;
end;

end.



0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Expert Comment

by:inter
ID: 1360237
Sorry, I think you create a thread when one request comes and needs processing. Them complete thread can be:

procedure TMyThread.Execute;
var
  Done : boolean;
  NeedsProcessing : boolean;
  FinishedProcessing : boolean;
begin
  Done := false;
  NeedsProcessing := true;
  FinishedProcessing := false;
  while not Done do
  begin
    if NeedsProcessing then
    begin
      MyCs.Lock;
      MyTable := GetIdleTable;
      if MyTable <> nil then
      begin
        // Process the table here
        // Signal For release
        NeedsProcessing := False;
        FinisgedProcessing := True; // querry to release table
      end;  
      MyCs.UnLock;
    end;
    if FinishedProcessing then
    begin
      MyCs.Lock;
      ReleaseTable(MyTable);
      MyCs.Unlock;
      Done := true; //terminate thread
    end;
  end; //while not done
end;


Please notify me if you can I should leave in 20 mins
Igor
0
 
LVL 5

Expert Comment

by:inter
ID: 1360238
Or in simplified form:(actually there is a bug in prev version:

procedure TMyThread.Execute;
var
  Done : boolean;
  NeedsProcessing : boolean;
begin
  Done := false;
  NeedsProcessing := true;
  while not Done do
  begin
    if NeedsProcessing then
    begin
      MyCs.Lock;
      MyTable := GetIdleTable;
      MyCs.UnLock; //unlock so other can acquire it
      if MyTable <> nil then // if nil wait for next pass
      begin
        // Process the table here
........................  
        // Signal For release
        NeedsProcessing := False;
        MyCs.Lock;
        ReleaseTable(MyTable);
        MyCs.Unlock;
        Done := true; //terminate thread
      end; // if table...
    end; // if needs...
  end; //while not done...
end;

Regards,
Igor
0
 

Author Comment

by:chrb
ID: 1360239
I am going to access it from ISAPI extension. But will the database actions take place in the thread called from, or in the thread created ? And I heard something about database sessions when using it in theads? I will try you code. Thanks!

Chr
0
 
LVL 5

Expert Comment

by:inter
ID: 1360240
Hi,

I really do not program with ISAPI. But done something very much like above with RPC. So the code above is a bit elaborated pseudo-code, there may be some bugs but the idea is there. By now thats all I can.

Have a nice day
Igor
0
 

Author Comment

by:chrb
ID: 1360241
Anyway you have given me a very good push. So send a message as anwear.
0
 
LVL 5

Accepted Solution

by:
inter earned 200 total points
ID: 1360242
Hi friend, and Thanks

You may reject and wait for an elaborated answer. Anyway, thanks. Need anything special or that I can help(do not forget include your nickname so that I know):

Redards
inter@kosgeb.tekmer.gov.tr
Igor
0

Featured Post

Secure Your Active Directory - April 20, 2017

Active Directory plays a critical role in your company’s IT infrastructure and keeping it secure in today’s hacker-infested world is a must.
Microsoft published 300+ pages of guidance, but who has the time, money, and resources to implement? Register now to find an easier way.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question