Reputation: 303
I have class named Myclass which has a 'Step' method and the other method as 'timer'. Below is the code for both methods. 'initialize' method starts Stepping. Aim is to calculate amount of time (in milliseconds) it took for 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.
Above code is working fine , but when i try to return the value of result, it gives me an error saying block cannot return. Is it possible to make process wait until result gets updated and get the value of result.
Upvotes: 0
Views: 266
Reputation: 3110
If all you want is know the time it took since last stepping, have a look at the FrameRateMorph
. It holds two instance variables, lastDisplayTime
and framesSinceLastDisplay
, which are calculated in the Morph’s #step
method:
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]
You can use similar logic in your morph.
Note that FrameRateMorph
implements #stepTime
to return 0
, so that it is called as often as possible. You might need to adjust your calculations according to this number.
If your goal cannot be achieved by the means above, you have three options.
Do you really need the fork in #timer
? What about this:
Myclass>>#timer
tstart:=Time millisecondClockValue.
sem:= Semaphor new.
sem wait.
Transcript show: result.
^ result
This will block until your result is ready.
If you insist on using a forked block, consider #forkAndWait
:
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result] forkAndWait.
^ result
This will also block until your result is ready.
You could proactively call code once your result is ready
Callback via argument
Pass a one-argument-block to a changed timer function and operate on the result:
Myclass>>#timerDo: aBlock
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
aBlock value: result] fork.
and then
| 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 block via instance variable
Add an instance variable, eg callBack
to Myclass
and change #timer
to
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
callBack value: result] fork.
and then use it like
| 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.
Callback via message send
Note this might be dangerous and not what you are after
The third option is not to save a block as callback but send a message to an object directly upon result arrival.
Add two instance variable, eg target
and selector
to Myclass
and change #timer
to
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
target perform: selector with: result] fork.
and then use it like
| obj |
" assume that obj is an instance of Myclass"
obj
target: blaObject;
selector: #showResult: .
obj timer.
However, with all process synchronization you can get yourself into all different kinds of trouble, so if possible, please try the first option first.
Upvotes: 1
Reputation: 2589
When you send the message fork
in MyClass>>timer
, a new process is created to evaluate the block and the timer
method exits immediately. That means you just can not return something from within the block because nobody is waiting for a value. If you explain us what you want to achieve, we might be able to better help.
Upvotes: 2