一个多线程的DEMO代码编写

Mit1208 2010-07-14 11:05:46
我想使用TThread类
启动5个线程,向listbox内写入1-100000的数值.
如何解决VCL和全局变量同步的问题呢?
能不能帮我写个Demo.
...全文
3344 45 打赏 收藏 转发到动态 举报
写回复
用AI写文章
45 条回复
切换为时间正序
请发表友善的回复…
发表回复
badmonkey1 2011-01-03
  • 打赏
  • 举报
回复
我正想学习、学习
jiemsoft 2010-07-19
  • 打赏
  • 举报
回复
进行中....
zgbj999 2010-07-19
  • 打赏
  • 举报
回复
[Quote=引用 41 楼 hexpate 的回复:]
引用 39 楼 zhaodog 的回复:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
lst1: TListBox;
……
[/Quote]
学习
xiven 2010-07-18
  • 打赏
  • 举报
回复
[Quote=引用 41 楼 hexpate 的回复:]
[/Quote]

学习了 谢谢 hexpate
Mit1208 2010-07-16
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 sanguomi 的回复:]
我的要求是动态创建5个线程,让这5个线程写入1-100000的值
而不是创建5个线程分别向listbox内写入1-100000的值.
----------------------------
我语文水平差, 看了几次都没看明白你到底要个什么东西
[/Quote]


嘿嘿.不光是你,我写的我看了几遍自己还有些迷糊呢.
意思就是创建的5个线程就在listbox内显示1-10000的数值.
而不是创建5个线程,让listbox内显示5次1-10000的数值
sanguomi 2010-07-16
  • 打赏
  • 举报
回复
我的要求是动态创建5个线程,让这5个线程写入1-100000的值
而不是创建5个线程分别向listbox内写入1-100000的值.
----------------------------
我语文水平差, 看了几次都没看明白你到底要个什么东西
Hexpate 2010-07-16
  • 打赏
  • 举报
回复
[Quote=引用 39 楼 zhaodog 的回复:]
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
lst1: TListBox;
btn1: TButto……
[/Quote]
我辛苦给你写个对的, 你给的分这么少, 人家写的有问题的反而那么多, 唉, 以后不会再这么热心了....., 记住了多线程是一个极易让人进入误区的, 还需要你多理解, 多测试, 你还没遇到多核, 还有CPU乱序等问题呢, 这些都是会影响很大的东西, 慢慢就知道了
lyflcear 2010-07-16
  • 打赏
  • 举报
回复
用TIMER控制一下,不然一定死;
Mit1208 2010-07-16
  • 打赏
  • 举报
回复
谢谢33楼的朋友.
继续等几天,看是否还有比你的更简单的代码吧!没有的话,分就全给你吧!
jbz001 2010-07-16
  • 打赏
  • 举报
回复
刚好,看看~!
zhaodog 2010-07-16
  • 打赏
  • 举报
回复
unit Unit1;

interface

uses
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.
Hexpate 2010-07-16
  • 打赏
  • 举报
回复

unit Unit13;

interface

uses
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的顺序输出, 而不是乱序的.
rslxy 2010-07-15
  • 打赏
  • 举报
回复
至少一个 不妥当的用法:
在FCS.Enter后,没有使用 Try ... Finally FCS.Leave End
Hexpate 2010-07-15
  • 打赏
  • 举报
回复
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;

我们看一下这段代码, 这个时候你可以在界面上加一个按钮, 按钮里写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不会被别人操作, 就像主线程随时可以操作它
Hexpate 2010-07-15
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 liangqingzhi 的回复:]
代码有误?求解释:)
我的经验是利用临界区加锁和解锁配对就不会出现死锁, Synchronize无非也就是EnterCriticalSection
处理方法完毕后再LeaveCriticalSection
[/Quote]

首先, 对于临界区的操作应该是防止多线程共享访问带来的灾难, 可是你把临界区放在线程内部当作一个成员变量, 那么每个线程访问的都是自己的临界区对象, 这样根本不存在同步, 也就是说这样做是毫无用处的, 其次是对于VCL的对象操作一直我们都说同步这是一种小误区, 实际应该说VCL的对象操作都需要交给主线程操作才对, 所以大家才会有误区认为线程同步好了就算是ok了, 真正理解还是需要仔细想想的, 换句话来说我们大家来想想对于一个vcl对象, 主线程随时都能访问它, 你怎么保证另外一个线程操作它时主线程不能访问它??方法只有一个, 就是把操作它的代码干脆交给主线程来做. 这是最 干净的办法.
老之 2010-07-15
  • 打赏
  • 举报
回复
代码有误?求解释:)
我的经验是利用临界区加锁和解锁配对就不会出现死锁, Synchronize无非也就是EnterCriticalSection
处理方法完毕后再LeaveCriticalSection
Hexpate 2010-07-15
  • 打赏
  • 举报
回复
顺便说一下, 对于你的这个问题我建议直接写在主线程里, 不要再开额外线程, 如果你怕锁死界面, application.processmessage 在这里正是用的时机.
Hexpate 2010-07-15
  • 打赏
  • 举报
回复
[Quote=引用楼主 lovemit 的回复:]
我想使用TThread类
启动5个线程,向listbox内写入1-100000的数值.
如何解决VCL和全局变量同步的问题呢?
能不能帮我写个Demo.
[/Quote]

兄弟, 首先线程这样用是明显的误区, 你的工作很简单, 完全是操作VCL对象, 这样的情况下必须要和VCL同步才可以, 如果是5个线程完全是浪费, 因为他们都被同步到主线程中去执行了. 如果你只是学使用方法, 2楼的帖子也是明显错误的, 坏的情况下是会导致死机的, 对于线程与VCL控件之间的协同必须交给Synchronize来做, 这个已经是常识了.
dinoalex 2010-07-15
  • 打赏
  • 举报
回复
你要五个线程写五个1-100000, 不是五个线程写一个1-100000 ??
nkym0626 2010-07-15
  • 打赏
  • 举报
回复
学习了
加载更多回复(22)

16,749

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧