Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Oct : Re: Multi-Threading

www.cryer.info
Managed Newsgroup Archive

Re: Multi-Threading

Subject:Re: Multi-Threading
Posted by:"A Pham" (ho..@home.com)
Date:Mon, 16 Oct 2006 21:33:35

Here is the easy way. I try to show the logic so code will look a bit funny.

Have fun
A Pham

TWorkItem = class
public
  .......All your variables
  procedure AfterDownload;
  {
       .....Your codes
   }
  procedure BeforeDownload;
  {
       .....Your codes
   }
  procedure Download;
  {
       .....Your codes
   }
  destructor Destroy;
  {
    .....Free stuff that on constructor or manage by this object
    inherited Destroy;
  }
end;

TWorker = class(TThread)
protected
   FEvent: TSimpleEvent;
   FWorkList: TList;
   FCritialSection: TCriticalSection;
   procedure ClearList;
   {
      while FWorkList.Count > 0 do
      begin
        TObject(FWorkList[FWorkList.Count - 1]).Free;
        FWorkList.Delete(FWorkList.Count - 1);
      end;
    }
   procedure Execute; override;
   var
        WorkItem: TWorkItem ;
        HasWork: Boolean;
   {
        while not Terminated do
        begin
            if FEvent.WaitFor(INFINITE) = erSignal then
            begin
                if Terminated then
                    Break;
                FEvent.ResetEvent;
                repeat
                    FCritialSection.Lock;
                    if FWorkList.Count > 0 then
                    begin
                        FWorkItem:= TWorkItem(FWorkList[0]);
                        FWorkList.Delete(0);
                        HasWork:= True;
                    end
                    else
                    begin
                        HasWork:= False;
                        FWorkItem:= nil;
                    end;
                    FCritialSection.UnLock;
                    if FWorkItem <> nil then
                    begin
                        //Rember to use Synchronize only if access stuff to
main form, otherwise ignore by calling straight procedure such as
FWorkItem.BeforeDownload
                        Synchronize(FWorkItem.BeforeDownload);
                        Synchronize(FWorkItem.Download);
                        Synchronize(FWorkItem.AfterDownload);
                        FreeAndNil(FWorkItem);
                    end;
                until Terminated or (not HasWork);
            end;
        end;
    }
public
  constructor Create;
  {
     inherited Create(True);
     FEvent:= TSimpleEvent.Create;
     FWorkList:= TList.Create;
     FCriticalSection:= TCriticalSection.Create;
     Resume;
  }
  destructor Destroy;
  {
      ClearList;
      FreeAndNil(FEvent);
      FreeAndNil(FWorkList);
      FreeAndNil(FCritialSection);
      inherited Destroy;
   }
   procedure AddWork(AWorkItem: TWorkItem);
   {
       FCritialSection.Lock;
       FWorkList.Add(AWorkItem);
      FCritialSection.UnLock;
       FEvent.SetEvent;
   }
   procedure Terminate;
   {
        inherited Terminate;
        FEvent.SetEvent;
    }
end;


Main Form
onCreate;
{
    Worker := TWorker.Create;
}
onDestroy;
{
    Worker.Terminate;
}
onUserClickRequest;
{
  WorkItem:= TWorkItem.Create;
    ....set all variables

   Worker.AddWork(WorkItem);
}


"David Fealkoff" <fealkoff@iatinc.net> wrote in message
news:45333d95$1@newsgroups.borland.com...
> I am attempting to implement multithreading in an application but am
stuck.
> Below I have the elements of my code.
>
> 1) I've created 2 objects which I attempt to use to create a threaded HTTP
> connection with sync'd updates to the main app.
>
>   TSyncClass = class
>   protected
>     FWorkCount: integer;
>     FWorkCountMax: integer;
>     FStringStream: TStringStream;
>     procedure BeginDownload;
>     procedure UpdateDownload;
>     procedure EndDownload;
>   public
>     procedure DoSynchronize(AThread: TIDThread; AMethod: TThreadMethod);
>   end;
>
>   TDownloadThread = class(TidThread)
>   protected
>     procedure httpworkbegin(ASender: TObject; AWorkMode: TWorkMode;
> AWorkCountMax: Integer);
>     procedure httpwork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount:
> Integer);
>     procedure httpworkend(ASender: TObject; AWorkMode: TWorkMode);
>   public
>     frequestURL: string;
>     fhost: string;
>     fport: integer;
>     fstream: TStringStream;
>     procedure Run; override;
>   end;
>
> 2) The TSyncClass procedures follow
>
> {TSyncClass}
> procedure TSyncClass.BeginDownload;
> begin
>   frmDownload.pbarDownload.Min := 0;
>   frmDownload.pbarDownload.Max := FWorkCountMax;
> end;
>
> procedure TSyncClass.UpdateDownload;
> begin
>   frmDownload.pbarDownload.Position := FWorkCount;
> end;
>
> procedure TSyncClass.EndDownload;
> begin
>   frmSoundStage.StrStream.CopyFrom(FStringStream,FStringStream.Size);
> end;
>
> procedure TSyncClass.DoSynchronize(AThread: TIdThread; AMethod:
> TThreadMethod);
> begin
>   AThread.Synchronize(AMethod);
> end;
>
> 3) The TDownloadThread procedures follow
> {TDownloadThread}
> procedure TDownloadThread.Run;
> begin
>   with TIdHTTP.Create(nil) do
>   begin
>     try
>       //populate request header
>       Request.URL := frequestURL;
>       OnWork := httpwork;
>       OnWorkBegin := httpworkbegin;
>       OnWorkEnd := httpworkend;
>       Connect(fhost,fPort);
>
>       while connected do
>         Get(Request.URL, fstream);
>
>     finally
>       Free;
>     end;
>   end;//with
>   Stop;
> end;
>
> procedure TDownloadThread.httpworkbegin(ASender: TObject; AWorkMode:
> TWorkMode; AWorkCountMax: Integer);
> var
>   C: TSyncClass;
> begin
>   C := TSyncClass.Create;
>   try
>     with C do
>     begin
>       FWorkCountMax := AWorkCountMax;
>       DoSynchronize(self,BeginDownload);
>     end;
>   finally
>     C.Free;
>   end;//try
> end;
>
> procedure TDownloadThread.httpwork(ASender: TObject; AWorkMode: TWorkMode;
> AWorkCount: Integer);
> var
>   C: TSyncClass;
> begin
>   C := TSyncClass.Create;
>   try
>     with C do
>     begin
>       FWorkCount := AWorkCount;
>       DoSynchronize(self,UpdateDownload);
>     end;
>   finally
>     C.Free;
>   end;//try
> end;
>
> procedure TDownloadThread.httpworkend(ASender: TObject; AWorkMode:
> TWorkMode);
> var
>   C: TSyncClass;
> begin
>   C := TSyncClass.Create;
>   try
>     with C do
>     begin
>
FStringStream.CopyFrom(TDownloadThread(ASender).fstream,TDownloadThread(ASen
der).fstream.Size);
>       DoSynchronize(self, EndDownload);
>     end;
>   finally
>     C.Free;
>   end;//try
> end;
>
> 4) Main form code
>
>       downloadThread := TDownloadThread.Create;
>
>       try
>         with downloadThread frmMain do
>         begin
>           FreeOnTerminate := True;
>           frequestURL := 'http://' + frmSystemTest.edtServerHost.text +
':'
> +
>             frmSystemTest.edtServerPort.text + '/GetQueue?clid=' +
>
InttoStr(TProductionInfo(lbProductions.Items.Objects[lbProductions.ItemIndex
]).selectedclipid);
>           fhost := frmSystemTest.edtServerHost.Text;
>           fport := StrToInt(frmSystemTest.edtServerPort.Text);
>           Start;
>       finally
>          downloadThread.Free;
>       end;
>
> 5)  It all seemed pretty straightforward under the assumption that in my
> main form (shown above) when I call "Start" that the "Run" procedure
> happens.  By the way, I got the
> structure for this implementation off of the Internet so I don't know how
> valid it is.  The assumptions I made were that the "Run" procedure would
> run, the idHTTP events would subsequently trigger and
> I could use those events to (a) pass download status information (b)
capture
> the download stream to the main form after the "WorkEnd" event.  Clearly
my
> application fails at (b) and having not tried a multithreaded application
> before I couldn't detect that the threading actually occured.  That is
> setting breakpoints didn't seem to work.  So, if anyone could give me a
> pointer about where I'm going wrong or some little detail I'm missing or
> even a better way of doing this I'd appreciate it.
>
> David

Replies:

none

In response to:

www.cryer.info
Managed Newsgroup Archive