一、项目需求
建立多个线程,同时对多个不同的下载任务进行下载二、我目前的代码示例
unit main;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, ExtCtrls, StdCtrls, Spin, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP, IdAntiFreezeBase, IdAntiFreeze;type
TWeiBoThread=class(TThread)
private
// IdHttp_Sina:TIdHTTP;
fs:TStringStream;
UpdateFuncID:integer;
IsFinished:Bool;
// FURL:string ;
public
sURL,sFileSave:string;
ThreadSumCount:integer;
ThreadIndex:integer; //当前线程编号
WhatLV:TListView;// IsBusy:Bool; //是否正在忙
//
// // IsPause_WaitDial:Bool; //主线程是否发货了暂停的命令,如果是,要挂起线程
//
// RoundIndex:integer;
LVIndex, WebIndex:integer; constructor Create( CreateSuspended: Boolean);
destructor Destroy; override;
procedure Execute ; override;
procedure SendID(nID:string);
procedure ThreadDone( ); procedure UpdateListView();
end;
type
TfmMain = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
edtThreadCount: TSpinEdit;
Label2: TLabel;
btnInit: TButton;
Button1: TButton;
IdHTTP1: TIdHTTP;
IdAntiFreeze1: TIdAntiFreeze;
Button2: TButton;
Button3: TButton;
Button4: TButton;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
lvUserList: TListView;
mmLog: TMemo;
procedure btnInitClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
TaskSumNum,FinishedTask:Integer;
end;var
fmMain: TfmMain; MyThreadList: array of TWeiBoThread;implementation{$R *.dfm}{ TWeiBoThread }constructor TWeiBoThread.Create (CreateSuspended: Boolean);
begin
inherited Create(false); LVIndex:=0;
end;destructor TWeiBoThread.Destroy;
begin
Terminate; //TY inherited;
end;procedure TWeiBoThread.Execute;
var
idHttp_Sina: TIdHttp; myStream:TStringStream;
begin
//用此句在运行过程中就报错,未知原因。2011-8-16 //●●●问题点4
//FreeOnTerminate := True; {这可以让线程执行完毕后随即释放} if IsFinished then Exit;
myStream:= TStringStream.Create; UpdateFuncID:=1; //1表示显示开始时间
Synchronize( UpdateListView );
//WhatLV.Items[LVIndex].SubItems[1]:= '开始:' + FormatDateTime('hh:mm:ss',now ) ;
idHttp_Sina:= TIdHttp.Create(nil); idHttp_Sina.Get('http://www.163.com?' + IntToStr(LVIndex) , myStream );
//idHttp_Sina.Get('http://www.baidu.com?' + IntToStr(LVIndex) , myStream ); //华军软件园,不同的网页
// idHttp_Sina.Get('http://www.onlinedown.net/soft/' + IntToStr( 44800 + LVIndex) + '.htm' , myStream ); UpdateFuncID:=2; //1表示显示开始时间
Synchronize( UpdateListView );
myStream.SaveToFile( 'OutFile\' +
IntToStr(LVIndex) + '@' + FormatDateTime('hhmmss',now ) + '.txt'
) ; myStream.Free;
idHttp_Sina.Free; Sleep(100); IsFinished:=True; inc( fmMain.FinishedTask ); if fmMain.FinishedTask = fmMain.TaskSumNum then
begin fmMain.mmLog.Lines.Add('多线程完成时间:' + FormatDateTime('hh:mm:ss',now ) );
ShowMessage('所有任务都已完成!');
end;
inherited;
end;procedure TWeiBoThread.SendID(nID: string);
begin
//
end;procedure TWeiBoThread.ThreadDone;
begin
exit; WhatLV.Items[LVIndex].SubItems[1]:=
WhatLV.Items[LVIndex].SubItems[1] + '...ThreadDone:完成:' + FormatDateTime('hh:mm:ss',now ) ;
end;
procedure TWeiBoThread.UpdateListView;
begin
if UpdateFuncID=1 then
WhatLV.Items[LVIndex].SubItems[1]:= inttostr(LVIndex) + ' 开始:' + FormatDateTime('hh:mm:ss',now )
else if UpdateFuncID=2 then
begin
WhatLV.Items[LVIndex].SubItems[1]:=
WhatLV.Items[LVIndex].SubItems[1] + '...完成:' + FormatDateTime('hh:mm:ss',now ) ;
end;
//Synchronize()的作用? 多线程之间控制同步过程.比方说要访问一种资源时,避免同时操作.//synchronize是不可以带参数的。
end;//////////////////////procedure TfmMain.Button1Click(Sender: TObject); //建立线程
var
i:integer;
begin
Caption:= '多线程...'; TaskSumNum:= edtThreadCount.Value;
FinishedTask:=0; SetLength(MyThreadList, edtThreadCount.Value +1 ); //线程数量
mmLog.Lines.Add('多线程开始时间:' + FormatDateTime('hh:mm:ss',now ) ); for I := 1 to edtThreadCount.Value do
begin
MyThreadList[i] := TWeiBoThread.Create( false );
MyThreadList[i].LVIndex:= i-1;
MyThreadList[i].WhatLV:= lvUserList; // MyThreadList[i].FreeOnTerminate:=True;
// MyThreadList[i].OnTerminate:= MyThreadList[i].ThreadDone; //
end; for I := 1 to edtThreadCount.Value do
begin
//MyThreadList[i].Resume;
// MyThreadList[i].Start;
MyThreadList[i].Execute;
end; mmLog.Lines.Add('多线程呼叫完成,等待线程们处理,呼叫时间:' + FormatDateTime('hh:mm:ss',now ) );end;
procedure TfmMain.Button3Click(Sender: TObject); //挂起线程 //●●●问题点3
var
i:integer;
begin
for I := 1 to edtThreadCount.Value do
begin
// MyThreadList[i].Suspend;
if MyThreadList[i].Terminated=False then
MyThreadList[i].Suspended:= True; end;
end;procedure TfmMain.Button4Click(Sender: TObject); //继续线程
var
i:integer;
begin
for I := 1 to edtThreadCount.Value do
begin
MyThreadList[i].Resume; // .Suspend; //如果线程已终止,则无法暂停止
end;
end;procedure TfmMain.FormCreate(Sender: TObject);
begin
btnInit.Click;
end;procedure TfmMain.btnInitClick(Sender: TObject);
var
nIndex,i:integer;
begin
lvUserList.Items.Clear;
nIndex:=0;
for i := 0 to 1000 - 1 do
begin //产生1000个数字序列 inc(nIndex);
with lvUserList.Items.Add do
begin
Caption:= inttostr(nIndex);
SubItems.Add( 'Num' + inttostr(nIndex) ) ; SubItems.Add( '' ) ; end;
end;
end;
end.------------------------三、问题点
1、上述代码,为什么我的线程任务全部完成后,在ListView中,开头的1-2个任务还会重新执行一次?
2、假设我现在有1000个任务要下载,然后我建立了10个线程,是不是就是在 Execute 中,放一个For 循环,如下:
procedure TWeiBoThread.Execute;
....
Begin
For i:=1 to 任务总数 / 线程数 + 1
Begin
if i >= WhatLV.Items.Count then Exit; //这里面写原来的那些Execute语句体
End
End;
是这样重复去下载吗?3、问题3
以问题2为例,我现在假设下载完成 XX 个任务时,要重新拨号,那么,我要怎么挂起任务,然后等拨号成功后再继续执行?
我现在的方法是想在主程序中先检测是否需要重新拨号,如果是,就执行上面的 //●●●问题点3
3.1 但我发现假如某个线程正在执行中,它好像根本不暂停或挂起。
3.2 如果说是一个线程必须要execute完毕才能挂起,那我拨号完后,怎么让它从下一个循环继续开始?是自己去控制 For 语句的开始数值,还是线程有其它方法让程序继续? 3.3 我们挂起一个线程,再继续一个线程时,它是重新执行 Execute ,还是从原来线程没有完成的地方继续执行?
3.4 在线程们执行过程中,我要强行退出程序,又要怎么做?我发现好像程序都关闭i不了,非得全部执行完。
4、问题点4
//用此句在运行过程中就报错,未知原因。2011-8-16 //●●●问题点4
//FreeOnTerminate := True; {这可以让线程执行完毕后随即释放} 上述一行代码,我为什么一加上它,程序运行就会报内存错?
以上诸个问题,诚请过来人和大虾们指教!
谢谢!
建立多个线程,同时对多个不同的下载任务进行下载二、我目前的代码示例
unit main;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, ExtCtrls, StdCtrls, Spin, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP, IdAntiFreezeBase, IdAntiFreeze;type
TWeiBoThread=class(TThread)
private
// IdHttp_Sina:TIdHTTP;
fs:TStringStream;
UpdateFuncID:integer;
IsFinished:Bool;
// FURL:string ;
public
sURL,sFileSave:string;
ThreadSumCount:integer;
ThreadIndex:integer; //当前线程编号
WhatLV:TListView;// IsBusy:Bool; //是否正在忙
//
// // IsPause_WaitDial:Bool; //主线程是否发货了暂停的命令,如果是,要挂起线程
//
// RoundIndex:integer;
LVIndex, WebIndex:integer; constructor Create( CreateSuspended: Boolean);
destructor Destroy; override;
procedure Execute ; override;
procedure SendID(nID:string);
procedure ThreadDone( ); procedure UpdateListView();
end;
type
TfmMain = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
edtThreadCount: TSpinEdit;
Label2: TLabel;
btnInit: TButton;
Button1: TButton;
IdHTTP1: TIdHTTP;
IdAntiFreeze1: TIdAntiFreeze;
Button2: TButton;
Button3: TButton;
Button4: TButton;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
lvUserList: TListView;
mmLog: TMemo;
procedure btnInitClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
TaskSumNum,FinishedTask:Integer;
end;var
fmMain: TfmMain; MyThreadList: array of TWeiBoThread;implementation{$R *.dfm}{ TWeiBoThread }constructor TWeiBoThread.Create (CreateSuspended: Boolean);
begin
inherited Create(false); LVIndex:=0;
end;destructor TWeiBoThread.Destroy;
begin
Terminate; //TY inherited;
end;procedure TWeiBoThread.Execute;
var
idHttp_Sina: TIdHttp; myStream:TStringStream;
begin
//用此句在运行过程中就报错,未知原因。2011-8-16 //●●●问题点4
//FreeOnTerminate := True; {这可以让线程执行完毕后随即释放} if IsFinished then Exit;
myStream:= TStringStream.Create; UpdateFuncID:=1; //1表示显示开始时间
Synchronize( UpdateListView );
//WhatLV.Items[LVIndex].SubItems[1]:= '开始:' + FormatDateTime('hh:mm:ss',now ) ;
idHttp_Sina:= TIdHttp.Create(nil); idHttp_Sina.Get('http://www.163.com?' + IntToStr(LVIndex) , myStream );
//idHttp_Sina.Get('http://www.baidu.com?' + IntToStr(LVIndex) , myStream ); //华军软件园,不同的网页
// idHttp_Sina.Get('http://www.onlinedown.net/soft/' + IntToStr( 44800 + LVIndex) + '.htm' , myStream ); UpdateFuncID:=2; //1表示显示开始时间
Synchronize( UpdateListView );
myStream.SaveToFile( 'OutFile\' +
IntToStr(LVIndex) + '@' + FormatDateTime('hhmmss',now ) + '.txt'
) ; myStream.Free;
idHttp_Sina.Free; Sleep(100); IsFinished:=True; inc( fmMain.FinishedTask ); if fmMain.FinishedTask = fmMain.TaskSumNum then
begin fmMain.mmLog.Lines.Add('多线程完成时间:' + FormatDateTime('hh:mm:ss',now ) );
ShowMessage('所有任务都已完成!');
end;
inherited;
end;procedure TWeiBoThread.SendID(nID: string);
begin
//
end;procedure TWeiBoThread.ThreadDone;
begin
exit; WhatLV.Items[LVIndex].SubItems[1]:=
WhatLV.Items[LVIndex].SubItems[1] + '...ThreadDone:完成:' + FormatDateTime('hh:mm:ss',now ) ;
end;
procedure TWeiBoThread.UpdateListView;
begin
if UpdateFuncID=1 then
WhatLV.Items[LVIndex].SubItems[1]:= inttostr(LVIndex) + ' 开始:' + FormatDateTime('hh:mm:ss',now )
else if UpdateFuncID=2 then
begin
WhatLV.Items[LVIndex].SubItems[1]:=
WhatLV.Items[LVIndex].SubItems[1] + '...完成:' + FormatDateTime('hh:mm:ss',now ) ;
end;
//Synchronize()的作用? 多线程之间控制同步过程.比方说要访问一种资源时,避免同时操作.//synchronize是不可以带参数的。
end;//////////////////////procedure TfmMain.Button1Click(Sender: TObject); //建立线程
var
i:integer;
begin
Caption:= '多线程...'; TaskSumNum:= edtThreadCount.Value;
FinishedTask:=0; SetLength(MyThreadList, edtThreadCount.Value +1 ); //线程数量
mmLog.Lines.Add('多线程开始时间:' + FormatDateTime('hh:mm:ss',now ) ); for I := 1 to edtThreadCount.Value do
begin
MyThreadList[i] := TWeiBoThread.Create( false );
MyThreadList[i].LVIndex:= i-1;
MyThreadList[i].WhatLV:= lvUserList; // MyThreadList[i].FreeOnTerminate:=True;
// MyThreadList[i].OnTerminate:= MyThreadList[i].ThreadDone; //
end; for I := 1 to edtThreadCount.Value do
begin
//MyThreadList[i].Resume;
// MyThreadList[i].Start;
MyThreadList[i].Execute;
end; mmLog.Lines.Add('多线程呼叫完成,等待线程们处理,呼叫时间:' + FormatDateTime('hh:mm:ss',now ) );end;
procedure TfmMain.Button3Click(Sender: TObject); //挂起线程 //●●●问题点3
var
i:integer;
begin
for I := 1 to edtThreadCount.Value do
begin
// MyThreadList[i].Suspend;
if MyThreadList[i].Terminated=False then
MyThreadList[i].Suspended:= True; end;
end;procedure TfmMain.Button4Click(Sender: TObject); //继续线程
var
i:integer;
begin
for I := 1 to edtThreadCount.Value do
begin
MyThreadList[i].Resume; // .Suspend; //如果线程已终止,则无法暂停止
end;
end;procedure TfmMain.FormCreate(Sender: TObject);
begin
btnInit.Click;
end;procedure TfmMain.btnInitClick(Sender: TObject);
var
nIndex,i:integer;
begin
lvUserList.Items.Clear;
nIndex:=0;
for i := 0 to 1000 - 1 do
begin //产生1000个数字序列 inc(nIndex);
with lvUserList.Items.Add do
begin
Caption:= inttostr(nIndex);
SubItems.Add( 'Num' + inttostr(nIndex) ) ; SubItems.Add( '' ) ; end;
end;
end;
end.------------------------三、问题点
1、上述代码,为什么我的线程任务全部完成后,在ListView中,开头的1-2个任务还会重新执行一次?
2、假设我现在有1000个任务要下载,然后我建立了10个线程,是不是就是在 Execute 中,放一个For 循环,如下:
procedure TWeiBoThread.Execute;
....
Begin
For i:=1 to 任务总数 / 线程数 + 1
Begin
if i >= WhatLV.Items.Count then Exit; //这里面写原来的那些Execute语句体
End
End;
是这样重复去下载吗?3、问题3
以问题2为例,我现在假设下载完成 XX 个任务时,要重新拨号,那么,我要怎么挂起任务,然后等拨号成功后再继续执行?
我现在的方法是想在主程序中先检测是否需要重新拨号,如果是,就执行上面的 //●●●问题点3
3.1 但我发现假如某个线程正在执行中,它好像根本不暂停或挂起。
3.2 如果说是一个线程必须要execute完毕才能挂起,那我拨号完后,怎么让它从下一个循环继续开始?是自己去控制 For 语句的开始数值,还是线程有其它方法让程序继续? 3.3 我们挂起一个线程,再继续一个线程时,它是重新执行 Execute ,还是从原来线程没有完成的地方继续执行?
3.4 在线程们执行过程中,我要强行退出程序,又要怎么做?我发现好像程序都关闭i不了,非得全部执行完。
4、问题点4
//用此句在运行过程中就报错,未知原因。2011-8-16 //●●●问题点4
//FreeOnTerminate := True; {这可以让线程执行完毕后随即释放} 上述一行代码,我为什么一加上它,程序运行就会报内存错?
以上诸个问题,诚请过来人和大虾们指教!
谢谢!
2.使用while not terminated do这样的去判断是否终止吧,里边加入你想跳出循环的一个判断语句
3.1应该是你的代码有问题吧,应该可以挂起的。
3.2拨号完后直接使用唤醒就行了
3.3从原来线程没有完成的地方执行
3.4如果是线程的话,怎么会关闭不了呢?是不是线程没有用对?关闭线程可以使用TThread.Terminate;然后TThread.Free;释放线程。
4.如果使用Freeonterminate的话就不要使用TThread.Free这样的了,会提示访问句柄错误的。
如果在线程执行的时候想关闭程序,就先判断一下线程是否正在运行,如果正在运行则TThread.Terminate,然后再TThread.Free;