5,388
社区成员
发帖
与我相关
我的任务
分享
Tb = class(TThread)
private
CS: TCriticalSection; //临界区对象
mm: TMemo; //用于显示的memo
fshowvalue: string; //用于显示的数据
procedure showmm(); //显示数据过程
procedure setshowvalue(const Value: string); //设置显示数据的过程
protected
procedure Execute; override;
public
constructor Create(mmo: TMemo); //创建时传入显示控件
destructor Destroy; override;
procedure Next(); //显示下一个输入的数据
property showvalue: string read fshowvalue write setshowvalue;//设置显示的数据
end;
implementation
{ Tb }
constructor Tb.Create(mmo: TMemo);
begin
inherited Create(True);
mm := mmo;
CS := TCriticalSection.Create;
fshowvalue := '';
Resume;
end;
destructor Tb.Destroy;
begin
CS.Leave;
CS.Free ;
inherited;
end;
procedure Tb.Execute;
begin
inherited;
while True do
begin
Synchronize(showmm);
Application.ProcessMessages ;
end;
end;
procedure Tb.showmm;
begin
if fshowvalue <> '' then //不输出空串
mm.Lines.Add(fshowvalue);
end;
procedure Tb.Next;
begin
CS.Leave ; //离开临界区
end;
procedure Tb.setshowvalue(const Value: string);
begin
CS.Enter; //进入临界区,应该只要没有离开临界区,这段
//代码就不应该被重复执行,而是等待上次调用
//离开临界区
//但实际上,只要进入这个过程就会往下执行,
//临界区对象似乎完全没有作用,为什么???
mm.Lines.Clear;
fshowvalue := Value;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
bb := Tb.Create(Mmo1); //创建线程
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
bb.showvalue := Edit1.Text ; //设置要显示的数据
end;
procedure TForm1.Button6Click(Sender: TObject);
begin
bb.Next ; //显示下一个数据
end;
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Unit2, SyncObjs;
type
Tc = class(TThread)
private
updates1: Tupdate;
fshowvalue: string;
FTag: Integer;
procedure setshowvalue(const Value: string); //用于显示的数据
protected
procedure Execute; override;
public
constructor Create(updates: Tupdate); //创建时传入显示控件
destructor Destroy; override;
property showvalue: string read fshowvalue write setshowvalue; //设置显示的数据
property Tag: Integer read FTag write FTag;
end;
implementation
uses Unit1;
{ Tc }
constructor Tc.Create(updates: Tupdate);
begin
inherited Create(True);
FreeOnTerminate := false;
updates1 := updates;
Resume;
end;
destructor Tc.Destroy;
begin
inherited;
end;
procedure Tc.Execute;
begin
inherited;
// CS.Enter ; //启用这行Enter,同时注释掉setshowvalue的Enter,第二个进入的线程就会在这里等待
//为什么?为什么Enter必须放在Execute中执行才会有效?
while True do
begin
updates1(fshowvalue);
end;
end;
procedure Tc.setshowvalue(const Value: string);
begin
CS.Enter ;
fshowvalue := Value;
end;
end.
调用处代码:
procedure TForm1.Button18Click(Sender: TObject);
begin
cc1 := Tc.Create(updates);
cc2 := Tc.Create(updates);
end;
procedure TForm1.updates(value: string);
begin
if value = '' then Exit;
Mmo1.Lines.Add(value);
end;
procedure TForm1.Button14Click(Sender: TObject);
begin
cc1.showvalue := '1111111';
end;
procedure TForm1.Button15Click(Sender: TObject);
begin
cc2.showvalue := '999';
end;
procedure TForm1.Button9Click(Sender: TObject);
begin
CS.Leave;
end;
其中线程对象cc1、cc2,临界区对象CS,都是全局定义的,CS以创建。
运行结果是:先后点击Button14、Button15,Mmo1中1111111和999交替显示,显然第二个线程的setshowvalue中的Enter没有起作用。
然后我又做测试,把setshowvalue过程中的Enter注释掉,改写在线程的Execute中,临界区Enter起作用了,这是为什么?我的代码中有什么问题吗?后来又做了些测试,就是把Enter放在不同地方调用,似乎只在Execute中才能起作用,为什么?type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
procedure DoShowData;
public
end;
var
Form1: TForm1;
CS: TCriticalSection;
dwDest : LongWord;
dwThreadCount : integer;
implementation
{$R *.dfm}
type
TAddThread = class(TThread)
private
protected
procedure Execute; override;
end;
procedure TAddThread.Execute;
var
i : integer;
begin
FreeOnTerminate := True;
CS.Enter;
Inc(dwThreadCount); //线程计数,多少个线程进入
CS.Leave;
for i := 1 to 30000000 do begin
CS.Enter; //如果注释掉这句和Leave那句,看结果
dwDest := dwDest + 1;
CS.Leave; //如果注释掉这句和Leave那句,看结果
end;
CS.Enter;
Dec(dwThreadCount);
if dwThreadCount=0 then //最后一个结束的线程显示数据
Synchronize(Form1.DoShowData);
CS.Leave;
end;
procedure TForm1.DoShowData;
begin
Memo1.Lines.Add(IntToStr(dwDest));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
dwDest := 0;
CS := TCriticalSection.Create;
TAddThread.Create;
TAddThread.Create;
end;
这个代码给你掩饰临界区的作用,如果注释掉for循环中的临界区那2句,看结果是否=60000000,同时可以看到怎么显示同步到主线程操作界面控件
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Unit2, SyncObjs;
type
Tc = class(TThread)
private
updates1: Tupdate;
fshowvalue: string;
procedure setshowvalue(const Value: string); //用于显示的数据
protected
procedure Execute; override;
public
constructor Create(updates: Tupdate); //创建时传入显示控件
destructor Destroy; override;
property showvalue: string read fshowvalue write setshowvalue; //设置显示的数据
end;
implementation
{ Tb }
constructor Tc.Create(updates: Tupdate);
begin
inherited Create(True);
updates1 := updates;
Resume;
end;
destructor Tc.Destroy;
begin
inherited;
end;
procedure Tc.Execute;
begin
inherited;
while True do
begin
updates1(fshowvalue);
Application.ProcessMessages ;
end;
end;
procedure Tc.setshowvalue(const Value: string);
begin
cs.Enter ; //设置显示数据时,进入临界区,在没有离开临界区前,
//其他线程应该不能再进入。
//实际上,没有leave临界区,每个线程都能轻松进入该过程
fshowvalue := Value;
end;
end.
调用代码:
type
Tupdate = procedure(value: string) of object;
TForm1 = class(TForm)
...
private
{ Private declarations }
procedure updates(value: string); //更新memo的过程
public
{ Public declarations }
CS: TCriticalSection; //临界区对象
end;
implementation
procedure TForm1.FormCreate(Sender: TObject);
begin
CS := TCriticalSection.Create;
cc1 := Tc.Create(updates);
cc2 := Tc.Create(updates);
end;
procedure TForm1.updates(value: string);
begin
if value = '' then Exit;
CS.Enter;
Mmo1.Lines.Add(value);
end;
procedure TForm1.Button14Click(Sender: TObject);
begin
cc1.showvalue := '1111111';
end;
procedure TForm1.Button15Click(Sender: TObject);
begin
cc2.showvalue := '999';
end;
procedure TForm1.Button9Click(Sender: TObject);
begin
Mmo1.Lines.Clear ;
CS.Leave;
end;
期望:
点击Button14,mmo1开始显示'1111111',此时点击Button15,没有任何反应。点击Button9,离开临界区,mmo1开始显示'999'。
实际结果:
点击Button14,mmo1开始显示'1111111',此时点击Button15,mmo1开始显示'1111111'、'999'交错显示,Button9点不点,都不影响结果,跟踪代码,点击Button15,之前的临界区并没有离开,可代码仍然通行无阻,为什么?求助。。。