请教:如何通过进程中的一个全局变量控制两个子线程互斥?谢谢! ( 积分: 50 )

  • 主题发起人 主题发起人 chenshu_sc
  • 开始时间 开始时间
C

chenshu_sc

Unregistered / Unconfirmed
GUEST, unregistred user!
我的程序如下:
unit FormMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
th1 = class(TThread)
s : string;
FStatus : Integer;
FMemo : TMemo;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

th2 = class(TThread)
s : string;
FStatus : Integer;
FMemo : TMemo;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
i : Integer;
t1 : th1;
t2 : th2;
end;

var
Form1: TForm1;
implementation
{$R *.dfm}
procedure th1.w;
begin
try
if FStatus = 1 then
begin
FStatus := 2;
sleep(1000);
s := 'TH1';
FStatus := 1;
end;
finally
end;
end;

procedure th1.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure th1.Execute ;
begin
while not terminateddo
begin
w;
Synchronize(showresult);
end;
end;

constructor th1.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited Create(Suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
end;

procedure th2.w;
begin
try
if FStatus = 1 then
begin
FStatus := 2;
sleep(300);
s := 'TH2';
FStatus := 1;
end;
finally
end;
end;

procedure th2.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure th2.Execute ;
begin
while not terminateddo
begin
w;
Synchronize(showresult);
end;
end;

constructor th2.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited create(suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
i := 1;
t1 := th1.Create(false,i,memo1);
t2 := th2.Create(false,i,memo1);
end;

end.

很明显没有达到要求,但不知道该怎么改?请各位大大帮忙!
 
我的程序如下:
unit FormMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
th1 = class(TThread)
s : string;
FStatus : Integer;
FMemo : TMemo;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

th2 = class(TThread)
s : string;
FStatus : Integer;
FMemo : TMemo;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
i : Integer;
t1 : th1;
t2 : th2;
end;

var
Form1: TForm1;
implementation
{$R *.dfm}
procedure th1.w;
begin
try
if FStatus = 1 then
begin
FStatus := 2;
sleep(1000);
s := 'TH1';
FStatus := 1;
end;
finally
end;
end;

procedure th1.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure th1.Execute ;
begin
while not terminateddo
begin
w;
Synchronize(showresult);
end;
end;

constructor th1.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited Create(Suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
end;

procedure th2.w;
begin
try
if FStatus = 1 then
begin
FStatus := 2;
sleep(300);
s := 'TH2';
FStatus := 1;
end;
finally
end;
end;

procedure th2.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure th2.Execute ;
begin
while not terminateddo
begin
w;
Synchronize(showresult);
end;
end;

constructor th2.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited create(suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
i := 1;
t1 := th1.Create(false,i,memo1);
t2 := th2.Create(false,i,memo1);
end;

end.

很明显没有达到要求,但不知道该怎么改?请各位大大帮忙!
 
procedure th1.w;
begin
try
if FStatus = 1 then
begin
FStatus := 3;
sleep(1000);
s := 'TH1';
FStatus := 2;
end;
finally
end;
end;

procedure th2.w;
begin
try
if FStatus = 2 then
begin
FStatus := 3;
sleep(300);
s := 'TH2';
FStatus := 1;
end;
finally
end;
end;
 
TO:lollman
 这样改了之后,线程不SLEEP啊。。。
 
另外,我感觉我目前的问题就是,如何在线程中改变进程中的全局变量?
 
楼主的问题用全局变量来解决是不正确的,因为全局变量不是线程安全的。
正确的方法是利用操作系统提供的互斥机制,因为线程/进程是由操作系统来调度的
DELPHI提供了相应的VCL对象来提供这种机制,楼主可以看看 TCriticalSection。
 
TO:沙隆巴斯的主人
  用TCriticalSection我也试过,但效果并不符合要求,因为感觉如果用TCriticalSection的话,t1/t2是分别等待对方运行完毕之后就运行,而不是根据FStatus的值来决定是否运行....
以下是我用TMultireadExclusiveWriteSynchronizer做的程序,还请多指教:
unit FormMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SyncObjs;
type
th1 = class(TThread)
s : string;
FStatus : Integer;
FMemo : TMemo;
// cs : TCriticalSection;
lj : TMultireadExclusiveWriteSynchronizer;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

th2 = class(TThread)
s : string;
FStatus : Integer;
FMemo : TMemo;
// cs : TCriticalSection;
lj : TMultireadExclusiveWriteSynchronizer;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

thPause = class(TThread)
s : String;
FStatus : Integer;
FMemo : TMemo;
// cs : TCriticalSection;
lj : TMultireadExclusiveWriteSynchronizer;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
i : Integer;
t1 : th1;
t2 : th2;
tPause : thPause;
end;

var
Form1: TForm1;
implementation
{$R *.dfm}
procedure th1.w;
begin
lj.begin
Read;
try
if FStatus = 1 then
begin
lj.begin
Write;
try
FStatus := 2;
sleep(2000);
s := 'TH1';
FStatus := 1;
// sleep(1000);
finally
lj.EndWrite;
end;
end;
finally
lj.EndRead;
end;
{
lj.begin
Write;
// cs.Enter;
try
if FStatus = 1 then
begin
FStatus := 2;
sleep(500);
s := 'TH1';
FStatus := 1;
sleep(1000);
end;
finally
// FStatus := 1;
lj.EndRead;
lj.EndWrite;
// cs.Leave;
end;
}
end;

procedure th1.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure th1.Execute ;
begin
while not terminateddo
begin
w;
Synchronize(showresult);
end;
end;

constructor th1.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited Create(Suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
// cs := TCriticalSection.Create;
lj := TMultireadExclusiveWriteSynchronizer.Create;
end;

procedure th2.w;
begin
lj.begin
Read;
try
s := IntToStr(FStatus);
if FStatus = 1 then
begin
lj.begin
Write;
try
FStatus := 2;
sleep(500);
// s := 'TH2';
FStatus := 1;
// sleep(1000);
finally
lj.EndWrite;
end;
end
else
begin
s := 'Th2 can not run cause FStatus <> 1!';
end;
finally
lj.EndRead;
end;
{
lj.begin
Read;
lj.begin
Write;
// cs.Enter;
try
if FStatus = 1 then
begin
FStatus := 2;
sleep(1000);
s := 'TH2';
FStatus := 1;
sleep(200);
end;
finally
// FStatus := 1;
lj.EndRead;
lj.EndWrite;
// cs.Leave;
end;
}
end;

procedure th2.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure th2.Execute ;
begin
while not terminateddo
begin
w;
Synchronize(showresult);
end;
end;

constructor th2.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited Create(Suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
// cs := TCriticalSection.Create;
lj := TMultireadExclusiveWriteSynchronizer.Create;
end;

procedure thPause.w;
begin
lj.begin
Read;
lj.begin
Write;
// cs.Enter;
try
FStatus := 0;
s := 'Pause';
finally
lj.EndRead;
lj.EndWrite;
// cs.Leave;
end;
end;

procedure thPause.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure thPause.Execute ;
begin
w;
Synchronize(showresult);
end;

constructor thPause.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited Create(Suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
// cs := TCriticalSection.Create;
lj := TMultireadExclusiveWriteSynchronizer.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
i := 1;
t1 := th1.Create(false,i,memo1);
t2 := th2.Create(false,i,memo1);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
tPause := thPause.Create(false,i,memo1);
end;

end.
 
另外重新说明一下我的问题:
  有两个线程t1、t2,一个全局变量status,当t1、t2运行的时候先判断status的值,如果为1的话继续,否则退出。在继续运行前status置为2,运行完毕后置为1。这样应该比较清楚了吧:)
  
 
to chenshu_sc:
用TCriticalSection来保护你的status就可以了啊。
 
cs.Enter;
FStatus := 2;
cs.Leave;
这不就结了?
 
TO:沙隆巴斯的主人&lichengbin
  谢谢两位的帮助,但我的问题好象并没有得到解决,因为我主要是想当程序运行的时候,th2有可能显示TH2也有可能显示'Th2 can not run cause FStatus <> 1!',而TCriticalSection是独占读写的,所以如果用TCriticalSection的话不太可能实现,只有改用TMultireadExclusiveWriteSynchronizer,因为它是共享读独占写。
  不过我写的程序好象并没有实现这个效果,以下是我将精简后的程序,请各位大大继续帮忙哈:)
unit FormMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SyncObjs;
type
th1 = class(TThread)
s : string;
FStatus : Integer;
FMemo : TMemo;
lj : TMultireadExclusiveWriteSynchronizer;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

th2 = class(TThread)
s : string;
FStatus : Integer;
FMemo : TMemo;
lj : TMultireadExclusiveWriteSynchronizer;
private
procedure w;
procedure showresult;
protected
procedure Execute ;
override;
public
constructor Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
end;

TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
i : Integer;
t1 : th1;
t2 : th2;
end;

var
Form1: TForm1;
implementation
{$R *.dfm}
procedure th1.w;
begin
lj.begin
Read;
try
if FStatus = 1 then
begin
lj.begin
Write;
try
FStatus := 2;
s := 'TH1';
sleep(1978);
FStatus := 1;
finally
lj.EndWrite;
end;
end;
finally
lj.EndRead;
end;
end;

procedure th1.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure th1.Execute ;
begin
while not terminateddo
begin
w;
Synchronize(showresult);
end;
end;

constructor th1.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited Create(Suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
lj := TMultireadExclusiveWriteSynchronizer.Create;
end;

procedure th2.w;
begin
lj.begin
Read;
try
if FStatus = 1 then
begin
lj.begin
Write;
try
FStatus := 2;
sleep(500);
s := 'TH2';
FStatus := 1;
finally
lj.EndWrite;
end;
end
else
begin
s := 'Th2 can not run cause FStatus <> 1!';
end;
finally
lj.EndRead;
end;
end;

procedure th2.showresult;
begin
FMemo.Lines.Add(s);
end;

procedure th2.Execute ;
begin
while not terminateddo
begin
w;
Synchronize(showresult);
end;
end;

constructor th2.Create(Suspended:Boolean ;
Status : Integer ;
mem : TMemo);
begin
inherited Create(Suspended);
FreeOnTerminate:=True;
FStatus := Status;
FMemo := mem;
lj := TMultireadExclusiveWriteSynchronizer.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
i := 1;
t1 := th1.Create(false,i,memo1);
t2 := th2.Create(false,i,memo1);
end;

end.
 
我知道为什么了,因为th1、th2中的FStatus它们是不同的变量....但怎么改呢?
 
根本搞不懂你在做什么?
首先,全局变量在哪里呀?FStatus只是线程内部的变量,创建一个线程对象,就有一个自己的FStatus变量,th1跟th2没看出来两者之间有任何联系,有任何同步互斥的必要!
其次,lj : TMultireadExclusiveWriteSynchronizer也是线程内部的变量,每创建一个线程,就新建了一个lj对象,那还谁跟谁同步呀,大家各管各的?怎么也要定义成全局变量才行的呀。
第三,只在需要访问共享资源的地方进行同步。
lj.begin
Write;
try
FStatus := 2;
sleep(500);
s := 'TH2';
FStatus := 1;
finally
lj.EndWrite;
end;
有必要这个样子吗?尤其还要Sleep转让控制权的。如果lj是全局的,如果其他线程也要写,那你这两个线程就死锁了
lj.begin
Write;
FStatus := 2;
lj.EndWrite;
sleep(500);
s := 'TH2';
lj.begin
Write;
FStatus := 1;
lj.EndWrite;
这样不就行了嘛。
第四,用CriticalSection完全就可以了,开销小,更有效率,没必要用TMultireadExclusiveWriteSynchronizer。
 
to chenshu_sc:
楼主的说的“全局变量”并是全局的,它们是对象内部成员,每个都占不同的空间。

按照楼主的设计思想,你应该在
var
Form1: TForm1;
FStatus : Integer;
//这个地方来定义全局变量
implementation
 
呵,都怪我没说清楚,还好 沙隆巴斯的主人 明白了我的意思:)
不过将FStatus改成Form1.i之后,th2好象一直无法执行,并CPU占用率一直是100%,这该怎么解决呢?
 
呵,搞定了,谢谢各位哈
 
多人接受答案了。
 
TO:lichengbin
 不好意思,分配错了,请到
  http://www.delphibbs.com/delphibbs/dispq.asp?lid=3177747
 领取:)
 谢谢!
 
后退
顶部