我有一个名为Myclass的类,它有一个'Step'方法,另一个方法是'timer'。以下是两种方法的代码。 'initialize'方法开始Stepping。目的是计算步进所花费的时间(以毫秒为单位)。
Myclass>> step
self bounds: ((self bounds) expandBy:1).
[(self extent )> (200@200) ifTrue:[self stopStepping.
tend:= Time millisecondClockValue.
result:= (tend-tstart).
Transcript cr; show: 'Semaphore signaled'.
sem signal. ]] fork.
Myclass>>timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
"^ result"] fork.
上面的代码工作正常,但是当我尝试返回结果的值时,它给出了一个错误,说块无法返回。是否有可能使进程等待直到结果更新并获得结果的值。
答案 0 :(得分:2)
当您在fork
中发送消息MyClass>>timer
时,会创建一个新流程来评估该块,并立即退出timer
方法。这意味着您无法从块内返回任何内容,因为没有人在等待值。如果您向我们解释您想要实现的目标,我们可能会提供更好的帮助。
答案 1 :(得分:1)
如果您想知道自上次踩踏后所花费的时间,请查看FrameRateMorph
。它包含两个实例变量lastDisplayTime
和framesSinceLastDisplay
,它们是在Morph的#step
方法中计算的:
FrameRateMorph>>#step
"Compute and display (every half second or so) the current framerate"
| now mSecs mSecsPerFrame framesPerSec newContents |
framesSinceLastDisplay := framesSinceLastDisplay + 1.
now := Time millisecondClockValue.
mSecs := now - lastDisplayTime.
(mSecs > 500 or: [mSecs < 0 "clock wrap-around"]) ifTrue:
[mSecsPerFrame := mSecs // framesSinceLastDisplay.
framesPerSec := (framesSinceLastDisplay * 1000) // mSecs.
"…"
lastDisplayTime := now.
framesSinceLastDisplay := 0]
您可以在变形中使用类似的逻辑。
请注意FrameRateMorph
实现#stepTime
以返回0
,以便尽可能频繁地调用它。您可能需要根据此数字调整计算。
如果您的目标无法通过上述方式实现,则有三种选择。
你真的需要#timer
中的分叉吗?那怎么样:
Myclass>>#timer
tstart:=Time millisecondClockValue.
sem:= Semaphor new.
sem wait.
Transcript show: result.
^ result
这将阻止,直到您的结果准备就绪。
如果您坚持使用分叉块,请考虑#forkAndWait
:
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result] forkAndWait.
^ result
这也会阻止,直到你的结果准备就绪。
您可以在结果准备好后主动调用代码
通过参数回调
将一个参数块传递给更改的计时器功能和 对结果进行操作:
Myclass>>#timerDo: aBlock
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
aBlock value: result] fork.
然后
| obj |
" assume that obj is an instance of Myclass"
obj timerDo: [:result |
"do something meaningful with the result, eg, show it "
blaObject showResult: result.].
通过实例变量回调块
将实例变量(例如callBack
)添加到Myclass
并将#timer
更改为
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
callBack value: result] fork.
然后像
一样使用它| obj |
" assume that obj is an instance of Myclass"
obj callBack: [:result |
"do something meaningful with the result, eg, show it "
blaObject showResult: result.].
obj timer.
通过短信发送回电
注意 这可能很危险,而不是你的目标
第三个选项不是将块保存为回调而是发送 在结果到达时直接向对象发送消息。
将两个实例变量(例如target
和selector
)添加到Myclass
并将#timer
更改为
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
target perform: selector with: result] fork.
然后像
一样使用它| obj |
" assume that obj is an instance of Myclass"
obj
target: blaObject;
selector: #showResult: .
obj timer.
但是,通过所有流程同步,您可以解决各种各样的问题,如果可能的话,请先尝试第一个选项。