发分啦:一个简单的例子谈Delphi类的静态局部变量 (300分)

  • 主题发起人 叮叮当当
  • 开始时间
To: liukun966123
我所要的变量,是所定义的过程本身所拥有的,和其他过程无关,这应该是个局部变量,但又要求是静态的,即退出过程后仍能维持其值。
 
hehe,你还钻牛角尖哪。
我说了一个静态变量或常量是没法与多个
特定的类的实例相联系的,这是由于它们在内存中的格局决定的.
 
呵呵,没办法的,暂时换个办法解决问题吧,
以后有空的话再慢慢研究哦
 
用信号防止重入
 
你的目的是什么?
->Function1是一个控件的事件(比如串行通信的接收事件),会被重复调用,我在Function1内部
->设置了一个静态局部变量AlreadyIn以[red]防止重入[/red]
就用一个互斥对象不就可以了吗?windows为我们提供了很好的编程资源,应当利用!
 
To: windbell
请就我上面的 Function1 过程讲解一下用互斥对象解决的办法。
BTW: Delphi里有现成的互斥对象可供使用么?
 
可以使用lock或是引用记数的方法

Lock Pattern
来源:
Lock 模式是建立在Delphi 中TStrings 类的更新锁定机制上的。
意图:
提供一种机制来临时锁定一个类的某些方面。
动机:
经常会出现一个对象在改变自身的内部状态后派发一些通知。用户为了与对象保持同步
必须处理这些通知。如果一次会做很多改变的话,那么会造成很多的通知和随之而来的同步
操作。Lock 模式让您暂时锁定一个类的某个方面,以阻止不希望的通知产生。Locking 可
以嵌套使用。
举一个实现聚合(比如:行为)的类TBag。每一次改变TBag 都将派发OnChange 时间。
如果我们要向一个bag 中增加多个对象,这就会产生多个通知。并且每一次都会让一个GUI
控件触发一次OnChange 事件,导致低效率。Lock 模式可以在增加对象之前锁定这个bag。
当对象增加完后,在将bag 解锁,这样就只用产生一个OnChange 的派发。使用Lock 模式
比设置一个布尔变量标志(比如:FUpdating)更好。因为Lock 模式和嵌套使用。
实现:
type
TBag = class (TObject)
private
FLockCnt: Integer;
protected
function Locked: Boolean;
procedure SetLocking(Updating: Boolean);
public
procedure Lock;
procedure UnLock;
end;
implementation
procedure TBag.Lock;
begin
Inc(FLockCnt);
if FLockCnt = 1 then SetLocking(False);
end;
function TBag.Locked: Boolean;
begin
Result := (FLockCnt <> 0);
end;
www.delphibbs.com
procedure TBag.SetLocking(Updating: Boolean);
begin
end;
procedure TBag.UnLock;
begin
Dec(FLockCnt);
if FLockCnt = 0 then SetLocking(True);
end;
注意:
&amp;sup2
FLockCnt 域存放锁定机制的状态。FLockCnt=0 表示一个解锁状态。其它的值暗指一个
锁定状态。允许嵌套调用Lock &amp
UnLocked 方法(这两个方法必须是唯一改变这个域的
方法)。
&amp;sup2
Lock &amp
UnLocked 方法提供锁定接口。每一次调用这两个会改变锁定状态的方法之一
时,方法SetLocking 都会被调用。
&amp;sup2
方法SetLocking 有一个Updating 参数。如果Updating 为true,这个bag 就调用UnLock
从而变为UnLocked 状态。如果Updating 为false,这个bag 就调用Lock 从而变为Locked
状态。您应当在这个方法中插入一些代码来处理锁定状态变化。
&amp;sup2
Locked 方法返回锁定机制的状态。
注意要成对地调用Lock 和UnLock,避免永远被锁。所以聪明的做法是用一个
try… finally 语句来保证成对地调用,如下所示:
procedure TBag.Add(Item: Pointer);
begin
{ Add Item to internal structure }
Change;
end
procedure TBag.AddItems(Items: TList);
begin
Lock;
{ Add multiple items }
try
for I := 0 to Items.Count - 1 do
Add(Items);
finally
{ use try..finally to make sure UnLock is called }
UnLock;
end;
end;
procedure TBag.Change;
begin
if not Locked then
if Assigned(FOnChange) then FOnChange(Self);
end;
procedure TBag.SetLocking(Updating: Boolean);
begin
if Updating then { Bag has become UnLocked }
Change;
end;
因为这种机制可以应用在很多种情况下,所以Lock 模式让您编辑模式的域和方法的名
称。有一些模式可以被不只一次地应用到同一个类上,并且仍然有意义,Lock 模式就是
其中一种。
 
procedure TMyObj.Function1;
begin
Function1 :=nil

.... // do something

end;
这样不行吗?
 
互斥对象是指一个异步对象,当它没有被一个线程拥有时其状态是信号状态,而当被线程拥有时其状态是无
信号状态。一次只能有一个线程拥有一个互斥量。互斥与临界区很相似,但是使用时相对复杂一些,它不仅
可以在同一应用程序的线程间实现同步,还可以在不同的进程间实现同步,从而实现资源的安全共享.
在Delphi中只对将事件对象和临界区对象封装为Tevent对象和TcritialSection对象,而对互斥对象并没有
提供可用的对象。

今天没时间了,明天再说吧![8D]
 
你真的是顽固不化,用一个类的私有成员不就可以解决了,死要钻牛角尖。
 
To: windbell
请教[8D]
 
不要说请教,我也只是将我的理解说一下,不对之处请大家多多指教[:)]

  由于在delphi中没有提供互斥对象,所以必须使用API来自己建立并维护。在建立互斥对象时,
可以指定一个唯一的名称(命名互斥对象)或者不指定名称(无名互斥对象),在不同的进程程中
要共享(不同进程间实现互斥)应该使用命名互斥对象。命名互斥对象的名称应该是全局唯一的,
不能和事件对象与临界区对象相同,否则将建立失败。 一个线程中可以使用CreateMutex函数来建
立互斥对象,并且在建立时可以立即申请拥有该对象,实现对资源的独占访问。在其它进程中的线
程要想拥有该互斥对象,可以调用openmutex函数来返回其句柄,该函数只有在其它进程已经建立
互斥对象后才能成功返回互斥对象的句柄。
  对一个互斥资源建立互斥对象后,线程就可以使用等待函数来请求访问该资源。当等待函数所
要求的互斥对象没有信号时,它就将线程阻塞(线程在阻塞状态下只占用极少的系统资源),直到
信号可用或者超时返回。等待函数分为三类,每一类中又有不同的几个函数,详细说明可以看
win32 sdk的帮助。
线程在处理完成自己的工作后,就当调用releasemutex函数来释放互斥对象以允许其它进程使用,
如果一个线程在终止前没有释放它所拥有的互斥对象,那么系统就认为这个互斥对象被抛弃,其它等
待的线程将获得其拥有权,但等待函数的返回值会标识出来此互斥对象被抛弃。此时有两种处理,一
种是假设进程出现错误,被保护的共享资源处于不可知的状态;另一种就是进行正常的操作,认为互
斥对象没有被抛弃,这时当线程释放掉对互斥对象的拥有权后互斥对象的错误状态被清除。
 
共享的又怎么能独立呢?
 
用静态方法来模拟
 
我记得以前有个函数因为老是会触发,然后一直调用,变成堆栈overflow,所以进入那函数
前,我也像你这样,定义成静态变量,判断是否已进入,然后。。。
但后来发现,自己犯了个低级错误,所以使那个函数会不断的触发。。。

我那个会触发的函数是:
Fields[0].OnValidate or
Fields[0].OnChange

Fields.AsString := ...
当程序调用Fields[1].AsString进行赋值时就会触发上面的事件,但在OnValidate,
OnChange事件中,我又调用了一次Fields[0].AsString := ...,这样变成死循环调用。。。
一直找不出问题。。。。后来才发现的。。。
 
不好意思!拖了这么久。虽然没更好的答案,我还是把这帖子结了吧。谢谢大家!
 

Similar threads

D
回复
0
查看
1K
DelphiTeacher的专栏
D
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
711
import
I
顶部