Solved

Hand out TTables

Posted on 1998-03-07
9
210 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
Technology Partners: 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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

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…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This is a high-level webinar that covers the history of enterprise open source database use. It addresses both the advantages companies see in using open source database technologies, as well as the fears and reservations they might have. In this…
There's a multitude of different network monitoring solutions out there, and you're probably wondering what makes NetCrunch so special. It's completely agentless, but does let you create an agent, if you desire. It offers powerful scalability …

688 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