Solved

Hand out TTables

Posted on 1998-03-07
9
197 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
 
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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
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

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

707 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

13 Experts available now in Live!

Get 1:1 Help Now