在信号量的帮助下返回一个值

时间:2013-09-11 06:43:14

标签: smalltalk pharo

我有一个名为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.

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

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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实现#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.

通过短信发送回电

注意 这可能很危险,而不是你的目标

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

将两个实例变量(例如targetselector)添加到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.

但是,通过所有流程同步,您可以解决各种各样的问题,如果可能的话,请先尝试第一个选项。