[email protected] wrote:
I thought this might be interesting to learn, so I've gave it a go. I
had some success at the end, but I'll give a progressive report.
First I thought I'd try moving the update of StringMorph outside the
worker-process using a Morph's #step method as follows...
Morph subclass: #BackgroundWorkDisplayMorph
instanceVariableNames: 'interProcessString stringMorph'
classVariableNames: ''
category: 'BenPlay'
"---------"
BackgroundWorkDisplayMorph>>initializeMorph
self color: Color red.
stringMorph := StringMorph new.
self addMorphBack: stringMorph.
self extent:(300@50).
"---------"
BackgroundWorkDisplayMorph>>newWorkerProcess
^[
| work |
work := 0.
[ 20 milliSeconds asDelay wait.
work := work + 1.
interProcessString := work asString.
] repeat.
] newProcess.
"---------"
BackgroundWorkDisplayMorph>>step
stringMorph contents: interProcessString.
"---------"
BackgroundWorkDisplayMorph>>stepTime
^50
"---------"
BackgroundWorkDisplayMorph>>initialize
| workerProcess running |
super initialize.
self initializeMorph.
workerProcess := self newWorkerProcess.
running := false.
self on: #mouseUp send: #value to:
[ (running := running not)
ifTrue: [ workerProcess resume. self color: Color green. ]
ifFalse: [ workerProcess suspend. self color: Color red. ]
]
"---------"
But evaluating "BackgroundWorkDisplayMorph new openInWorld" found this
exhibited the same problematic behavior you reported... Clicking on the
morph worked a few times and then froze the UI until Cmd-. pressed a
few times.
However I found the following never locked the GUI.
BackgroundWorkDisplayMorph>>initialize
"BackgroundWorkDisplayMorph new openInWorld"
| workerProcess running |
super initialize.
self initializeMorph.
workerProcess := self newWorkerProcess.
running := false.
[ [ (running := running not)
ifTrue: [ workerProcess resume. self color: Color green ]
ifFalse: [ workerProcess suspend. self color: Color red ].
10 milliSeconds asDelay wait.
] repeat ] fork.
"---------"
So the problem seemed to not be with #suspend/#resume or with the
shared variable /interProcessString/. Indeed, since in the worker
thread /interProcessString/ is atomically assigned a copy via
#asString, and the String never updated, I think there is no need to
surround use of it with a critical section.
The solution then was to move the "#resume/#suspend" away from the
"#on: #mouseUp send: #value to:" as follows...
BackgroundWorkDisplayMorph>>initialize
"BackgroundWorkDisplayMorph new openInWorld"
| workerProcess running lastRunning |
super initialize.
self initializeMorph.
workerProcess := self newWorkerProcess.
lastRunning := running := false.
[ [ lastRunning = running ifFalse:
[ running
ifTrue: [ workerProcess resume ]
ifFalse: [ workerProcess suspend ].
lastRunning := running.
].
10 milliSeconds asDelay wait.
] repeat ] fork.
self on: #mouseUp send: #value to:
[ (running := running not)
ifTrue: [ self color: Color green. ]
ifFalse: [ self color: Color red. ]
]
"---------"
And finally remove the busy loop.
BackgroundWorkDisplayMorph>>initialize
"BackgroundWorkDisplayMorph new openInWorld"
| workerProcess running lastRunning semaphore |
super initialize.
self initializeMorph.
workerProcess := self newWorkerProcess.
lastRunning := running := false.
semaphore := Semaphore new.
[ [ semaphore wait.
running
ifTrue: [ workerProcess resume ]
ifFalse: [ workerProcess suspend ].
] repeat ] fork.
self on: #mouseUp send: #value to:
[ (running := running not)
ifTrue: [ self color: Color green. ]
ifFalse: [ self color: Color red. ].
semaphore signal.
]
"---------"
Now I can't say how close that is to how it "should" be done. Its the
first time I used sempahores and just what I discovered hacking around.
But hey! it works :)
Actually, thinking further this morning, you don't need that extra
process running...
BackgroundWorkDisplayMorph>>initialize
| running workerStart |
super initialize.
self initializeMorph.
running := false.
workerStart := Semaphore new.
[ | work |
work := 0.
[ running ifFalse: [ workerStart wait ].
20 milliSeconds asDelay wait.
work := work + 1.
interProcessString := work asString.
] repeat.
] fork.
self on: #mouseUp send: #value to:
[ (running := running not)
ifTrue: [ self color: Color green. workerStart signal ]
ifFalse: [ self color: Color red ].
]
"---------"
cheers -ben
Nicolai Hess wrote:
I am still struggling with it.
Any ideas?
|