0

我有一个名为 Myclass 的类,它有一个“Step”方法,另一个方法是“timer”。下面是这两种方法的代码。'initialize' 方法开始步进。目的是计算步进所需的时间(以毫秒为单位)。

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.

上面的代码工作正常,但是当我尝试返回结果的值时,它给了我一个错误,说块无法返回。是否可以让进程等到结果更新并获取结果的值。

4

2 回答 2

2

当您发送消息forkMyClass>>timer,会创建一个新进程来评估该块,并且该timer方法会立即退出。这意味着你不能从块内返回一些东西,因为没有人在等待一个值。如果您向我们解释您想要实现的目标,我们可能会提供更好的帮助。

于 2013-09-11T09:35:11.840 回答
1

帧率

如果您只想知道自上次执行以来所用的时间,请查看FrameRateMorph. 它包含两个实例变量lastDisplayTimeframesSinceLastDisplay,它们是在 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实现#stepTimereturn 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.].

通过实例变量回调块

添加一个实例变量,例如callBacktoMyclass和 change #timerto

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.

通过消息发送回调

请注意 ,这可能很危险,而不是您所追求的

第三种选择不是将块保存为回调,而是在结果到达时直接向对象发送消息。

添加两个实例变量,例如targetand selectortoMyclass和 change #timerto

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.

但是,通过所有进程同步,您可能会遇到各种不同的麻烦,因此如果可能,请先尝试第一个选项。

于 2013-09-12T17:38:43.643 回答