Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Oct : 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
none