我想使用TThread类
启动5个线程,向listbox内写入1-100000的数值.
如何解决VCL和全局变量同步的问题呢?
能不能帮我写个Demo.
启动5个线程,向listbox内写入1-100000的数值.
如何解决VCL和全局变量同步的问题呢?
能不能帮我写个Demo.
解决方案 »
- delphi生成了可执行文件,再修改怎么办??
- 【请教】图像移动问题!
- 急。如何将foxpro2.6创建的DBF文件的内容批量倒入ACCESS文件中,并且自动在ACCESS文件中创建相应的表
- 寻求能将通过可视化生成的单元(包括界面)转换成封装好的类的工具
- rpc服务不可用
- 我想当点击任一表的记录时,另外的一个表也移动到与其相对应的记录......
- 100分求问一个问题???
- 请教关于DELPHI5和DELPHI6中datetimepicker控件的问题
- **** 讨论:各地的“乐敦”眼药水多少钱?*****
- 帮帮忙,把下面的程序改成C,delphi我不懂
- cxgrid如何读取文本并同步修改
- Delphi操纵WebBrowser问题
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SyncObjs;type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end; TMyThread = class(TThread)
public
FCS: TCriticalSection;
procedure Execute; override;
constructor Create;
destructor Destroy; override;
end;var
Form1: TForm1; i: Integer;implementation{$R *.dfm}{ TMyThread }constructor TMyThread.Create;
begin
FCS := TCriticalSection.Create;
self.FreeOnTerminate := True;
inherited Create(False);
end;destructor TMyThread.Destroy;
begin
FCS.Free;
inherited;
end;procedure TMyThread.Execute;
begin
inherited;
while i < 100000 do
begin
FCS.Enter;
i := i + 1;
Form1.ListBox1.Items.Add(IntToStr(i) + ':' + IntToStr(Handle));
//加上Handle可以看出是哪个线程添加的值
FCS.Leave;
end;
end;procedure TForm1.FormCreate(Sender: TObject);
begin
i := 0;
end;procedure TForm1.Button1Click(Sender: TObject);
var
a: TMyThread;
begin
a := TMyThread.Create;
a := TMyThread.Create;
a := TMyThread.Create;
a := TMyThread.Create;
a := TMyThread.Create;
end;end.
兄弟, 首先线程这样用是明显的误区, 你的工作很简单, 完全是操作VCL对象, 这样的情况下必须要和VCL同步才可以, 如果是5个线程完全是浪费, 因为他们都被同步到主线程中去执行了. 如果你只是学使用方法, 2楼的帖子也是明显错误的, 坏的情况下是会导致死机的, 对于线程与VCL控件之间的协同必须交给Synchronize来做, 这个已经是常识了.
我的经验是利用临界区加锁和解锁配对就不会出现死锁, Synchronize无非也就是EnterCriticalSection
处理方法完毕后再LeaveCriticalSection
首先, 对于临界区的操作应该是防止多线程共享访问带来的灾难, 可是你把临界区放在线程内部当作一个成员变量, 那么每个线程访问的都是自己的临界区对象, 这样根本不存在同步, 也就是说这样做是毫无用处的, 其次是对于VCL的对象操作一直我们都说同步这是一种小误区, 实际应该说VCL的对象操作都需要交给主线程操作才对, 所以大家才会有误区认为线程同步好了就算是ok了, 真正理解还是需要仔细想想的, 换句话来说我们大家来想想对于一个vcl对象, 主线程随时都能访问它, 你怎么保证另外一个线程操作它时主线程不能访问它??方法只有一个, 就是把操作它的代码干脆交给主线程来做. 这是最 干净的办法.
begin
inherited;
while i < 100000 do
begin
FCS.Enter;
i := i + 1;
Form1.ListBox1.Items.Add(IntToStr(i) + ':' + IntToStr(Handle));
//加上Handle可以看出是哪个线程添加的值
FCS.Leave;
end;
end;我们看一下这段代码, 这个时候你可以在界面上加一个按钮, 按钮里写Form1.ListBox1.Items.Add('111'); 线程在执行时如果不是使用Synchronize的话,主线程是可以随时对Form1.listbox1操作的,为什么, 因为这里没有任何一句代码可以告诉我们FCS.Enter执行后Listbox1是不能被别人操作的, 正确的使用临界区也只是保证 FCS.Enter;
i := i + 1;
Form1.ListBox1.Items.Add(IntToStr(i) + ':' + IntToStr(Handle));
//加上Handle可以看出是哪个线程添加的值
FCS.Leave;这里面的代码不会并行执行, 但是无法保证ListBox1不会被别人操作, 就像主线程随时可以操作它
在FCS.Enter后,没有使用 Try ... Finally FCS.Leave End
由8楼的代码能看出Handle是那个线程的吗?
先声明一下.我只是为了学习动态创建多个线程写入VCL的方法.
还有2楼的朋友,也谢谢你,我的要求是动态创建5个线程,让这5个线程写入1-100000的值
而不是创建5个线程分别向listbox内写入1-100000的值.此贴只是为了学习动态创建多个线程的方法,还希望各位能够给予帮助!
既然已经确定输出10000,那就用10000/5,每个线程分配一个起始累加数的地址,让各个线程去默默循环累加并把每个数记在各自线程中的一个TStringList中.在线程的onterminate中把该List赋给主线程中的LISTVIEW不就OK了?
unit Unit13;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SyncObjs;type
INumberGenerator = interface
['{C44CFFF2-D977-4388-B37D-F2BE324C967A}']
function Finished : Boolean;
function GenerateNextNumber: Integer;
end; TForm13 = class(TForm, INumberGenerator)
btn1: TButton;
lst1: TListBox;
btn2: TButton;
btn3: TButton;
procedure FormCreate(Sender: TObject);
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure btn3Click(Sender: TObject); private
fNumber : integer; { Private declarations }
public
function GenerateNextNumber: Integer;
function Finished: Boolean;
{ Public declarations }
end; TNumExportThread = class(TThread)
private
fList: TStrings;
fNumberGenerator: INumberGenerator;
procedure DoExportNumber;
protected
procedure Execute; override;
public
constructor Create(const list: TStrings; const numberGenerator: INumberGenerator);
end;var
Form13: TForm13;implementation{$R *.dfm}procedure TForm13.btn1Click(Sender: TObject);
var
i: integer;
generator: INumberGenerator;
begin
generator := Self as INumberGenerator;
for I := 1 to 5 do
TNumExportThread.Create(lst1.Items, generator);
end;procedure TForm13.btn2Click(Sender: TObject);
var
i: integer;
begin
// 最简单的方式, 不用线程 效率也是最高的.
lst1.Items.BeginUpdate;
try
for i := 0 to 10000 - 1 do begin
lst1.Items.Add(IntToStr(i));
end;
finally
lst1.Items.EndUpdate;
end;
end;procedure TForm13.btn3Click(Sender: TObject);
begin
ShowMessage(IntToStr(lst1.Items.Count));
end;function TForm13.GenerateNextNumber: Integer;
begin
inc(fNumber);
Result := fNumber;
end;procedure TForm13.FormCreate(Sender: TObject);
begin
fNumber := -1;
end;
{ TNumExportThread }constructor TNumExportThread.Create(const list: TStrings; const numberGenerator: INumberGenerator);
begin
fList := list;
fNumberGenerator := numberGenerator;
FreeOnTerminate := true;
inherited Create(False);
end;procedure TNumExportThread.DoExportNumber;
var
i : Integer;
begin
i := fNumberGenerator.GenerateNextNumber;
if not fNumberGenerator.Finished then begin
fList.Add(IntToStr(i)) ;
end;
end;procedure TNumExportThread.Execute;
begin
while not fNumberGenerator.Finished do begin
Synchronize(DoExportNumber);
end;
end;
function TForm13.Finished: Boolean;
begin
Result := fNumber > 10000;
end;initialization
ReportMemoryLeaksOnShutdown := true;
end.
值得注意是线程一般做Synchronize应该保证代码最小化, 也就是Synchronize的代码要最少, 例如只操作Vcl的部分, 上面的代码为什么还含有获取数字的代码部分呢, 那是因为为了保证5个线程是按1-10000的顺序输出, 而不是乱序的.
而不是创建5个线程分别向listbox内写入1-100000的值.
----------------------------
我语文水平差, 看了几次都没看明白你到底要个什么东西
意思就是创建的5个线程就在listbox内显示1-10000的数值.
而不是创建5个线程,让listbox内显示5次1-10000的数值
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
lst1: TListBox;
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end; TDemoThread=class(TThread)
private
FiCounter:Integer;
FiResult:Integer;
procedure Disaply();
protected
procedure Execute();override;
public
constructor Create(var Counter:Integer);
end;var
Form1: TForm1;implementation{$R *.dfm}
const
COUNTER_MAX:Integer=1000;
var
iCounter :Integer;{ TDemoThread }constructor TDemoThread.Create(var Counter: Integer);
begin
FiCounter:=Counter;
inherited Create(False);
FreeOnTerminate:=True;
end;procedure TDemoThread.Disaply;
begin
Form1.lst1.Items.Add( IntToStr(FiResult));
end;procedure TDemoThread.Execute;
begin
while not terminated do
begin
FiResult:= InterlockedIncrement(iCounter);
if FiResult<=COUNTER_MAX then
Synchronize(Disaply)
else
Break; end;
end;procedure TForm1.btn1Click(Sender: TObject);
var
i:Integer;
begin
for i:=0 to 4 do
begin
TDemoThread.Create(iCounter);
end;
end;end.