Solved

Hand out TTables

Posted on 1998-03-07
9
203 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
  • 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
Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

 
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

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

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

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.

813 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

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now