I need to stop a process from running longer than n seconds, so here's what I thought I'd do:
|aProcess|
aProcess := [ 10000 timesRepeat: [Transcript show: 'X'] ] fork.
[(Delay forSeconds: 1) wait. aProcess terminate] fork.
I thought this was the proper way to proceed, but it seems to fail from time to time, the Transcript just goes on printing Xes. What bugs me is that it does work sometimes and I can't figure out what the work/fail pattern is.
This is already in the library, you don't need to reinvent it.
[10000 timesRepeat: [Transcript show: 'X']]
valueWithin: 1 second onTimeout: [Transcript show: 'stop']
Both processes are running on the same priority, that's why the second process actually doesn't get chance to interrupt the first one at all. Try to run the first loop in lower priority or even better, second one in higher:
[(Delay forSeconds: 1) wait. aProcess terminate]
forkAt: Processor userInterruptPriority
Related
I'm trying to send the output of my code to an inactive application using Auto Hotkey on my computer so I don't have to be on the screen and can do other stuff. How would I go about implementing it?
F1::
stop := 0
Loop
{
Send, z
Sleep 500
}until Stop
return
F2::Stop := 1
This is the code I have down so far, any help?
ControlSending might work. It's basically a hit or miss. It'll work for some applications, and for some it wont.
It'll be worth a try for you though.
Also, you're going to want to use a timer as opposed to looping in a hotkey thread. Timer is intended just for something like this and what you were doing is kind of bad practice for various reasons.
;timer runs the user-defined function "SendZ" every 500ms
F1::SetTimer, SendZ, 500
F2::SetTimer, SendZ, Off
SendZ()
{
ControlSend, , z, % "ahk_exe notepad.exe"
}
As a bonus, we can even write a sweet one liner to toggle on/off that timer by using a ternary:
F1::SetTimer, SendZ, % (Toggle:=!Toggle) ? 500 : "Off"
If that doesn't make sense to you, and you're interested, you can read a lengthy previous explanation of mine about it here.
In many languages you can do something like the following:
while true:
handle events like keyboard input
update game world
draw screen
(optional: delay execution)
while this is far from optimal it should suffice for simple games.
How do you do this in Squeak Smalltalk?
I can read keyboard input and react to it as described on wiki.squeak.org. But if I try to execute something like
1 to: 10 do: [ :i | game updateAndDraw ]
all the events are only ever handled after the loop has executed.
Morphic already provides that main loop. It's in MorphicProject class>>spawnNewProcess:
uiProcess := [
[ world doOneCycle. Processor yield ] repeat.
] newProcess ...
And if you dig into doOneCycle you will find it
(optionally) does a delay (interCyclePause:)
checks for screen resize
processes events
processes step methods
re-displays the world
Your code should hook into these phases by adding mouse/keyboard event handlers, step methods for animation, and draw methods for redisplaying. All of these should be methods in your own game morph. You can find examples throughout the system.
To perform an action a fixed number of times:
10 timesRepeat: [game updateAndDraw]
To use while semantics:
i := 5
[i > 0] whileTrue: [
i printNl.
i := i - 1.
]
To create a perpetual loop using while semantics,
[true] whileTrue: [something do]
You should be able to take advantage of the Morphic event loop by using the Object >> #when:send:to: message.
I'm making a N*N queens problem with gui.
I want the gui to stop for x seconds each move of every queen, problem is, the program just stacks all the waits together and then runs everything at speed.
I'm giving the code here: http://pastebin.com/s2VT0E49
EDIT:
This is my workspace:
board := MyBoard new initializeWithStart: 8.
Transcript show:'something'.
3 seconds asDelay wait.
board solve.
3 seconds asDelay wait.
board closeBoard.
This is where i want the wait to happen
canAttack: testRow x: testColumn
| columnDifference squareMark |
columnDifference := testColumn - column.
((row = testRow
or: [row + columnDifference = testRow])
or: [row - columnDifference = testRow]) ifTrue: [
squareDraw := squareDraw
color: Color red.
0.2 seconds asDelay wait.
^ true ].
squareDraw := squareDraw color: Color black.
^ neighbor canAttack: testRow x: testColumn
Since you're using Morphic you should use stepping for animation, not processes or delays. In your Morph implement a step method. This will be executed automatically and repeatedly. Also implement stepTime to answer the interval in milliseconds, e.g. 4000 for every 4 seconds.
Inside the step method, calculate your new state. If each queen is modeled as a separate Morph and you just move the positions, then Morphic will take care of updating the screen. If you have your own drawOn: method then call self changed in your step method so that Morphic will later invoke your drawing code.
See this tutorial: http://static.squeak.org/tutorials/morphic-tutorial-1.html
The process you're suspending is the one your program is running in. This process also happens to be the UI process. So when you suspend your program you also suspend the UI and therefore the UI elements never get a chance to update themselves. Try running your program in a separate process:
[ MyProgram run ] forkAt: Processor userBackgroundPriority.
Note that the UI process usually runs at priority 40. #userBackgroundPriority is 30. This makes sure that you can't lock up the UI.
To make your workspace code work insert this before the delay:
World doOneCycle.
This will cause the Morphic world to be redisplayed.
Note that this is quick-and-very-dirty hack and not the proper way to do it (see my other answer). Delays block the whole UI process, whereas the whole point of Morphic is that you can do many things simultaneously while your code is executing.
I'm dealing with N*N queens problem and gui of it.
I want to sleep for a few seconds each move so the viewer can see the process.
How do I put smalltalk to sleep?
Thank you
Instead of sleeping you can just wait.
5 seconds asDelay wait.
e.g. if you select and print it the following, it will wait 5 seconds before printing the result (2)
[
5 seconds asDelay wait.
1 + 1
] value
The comment of the Delay class explains what it does.
I am the main way that a process may pause for some amount of time. The simplest usage is like this:
(Delay forSeconds: 5) wait.
An instance of Delay responds to the message 'wait' by suspending the caller's process for a certain amount of time. The duration of the pause is specified when the Delay is created with the message forMilliseconds: or forSeconds:. A Delay can be used again when the current wait has finished. For example, a clock process might repeatedly wait on a one-second Delay.
A delay in progress when an image snapshot is saved is resumed when the snapshot is re-started. Delays work across millisecond clock roll-overs.
For a more complex example, see #testDelayOf:for:rect: .
Update: (based on comment)
wait will pause the execution flow, which means that in the example earlier, the 1 + 1 will get executed (execution flow resumed) only after the wait period has ended.
So in your class you can have...
MyBoard>>doStep
self drawBoard.
5 seconds asDelay wait.
self solve.
5 seconds asDelay wait.
self destroyBoard.
I want to animate a dice being rolled, but don't want to use the Morph>>step methods because I want more control over when the roll finishes. I know that I can use Delay>>wait within a forked block to see my animation, but then how should I call this method from other methods to ensure I get the final numberRolled?
Here's my roll method:
roll
| n t |
numberRolled := nil.
[
t := 10 + (10 atRandom).
t timesRepeat: [
n := 6 atRandom.
self showNumber: n.
(Delay forSeconds: 0.1) wait.
].
numberRolled := n.
] fork.
So if I call this from a method like guessLower the roll method returns instantly because the real work is completed in the forked process.
guessLower
previousNumberRolled := numberRolled.
self roll.
"this next line is called before the dice has finished rolling"
self checkWin: (numberRolled < previousNumberRolled)
My current solution is to modify roll method to take a block, which that executes after the rolling has finished e.g. rollAndThen: aBlock but is there a more elegant / simpler solution?
In Morphic it is a Really Bad Idea to use Delays and explicit looping.
But it is really simple to make the step method do what you want: Inside you simply check if it should continue rolling or not. Then you do self stopStepping. self checkWin: ....