rb@otter.hpl.hp.com (Richard Brown) (05/16/91)
Does anyone have any code to do some simple time slicing. I want to ensure that a user background task that I have running is guaranteed at least 75% of the cpu time. In particular, I want to guard against locking the background task out by the user constantly moving the mouse. I have tried a few things but I keep locking up the user interface and then am forced to hit ^C. Any help is welcome. Richard Brown
rb@otter.hpl.hp.com (Richard Brown) (05/23/91)
Well I have had no response to this question so far, but this is the
solution that I have implemented. I am still having a few problems
with it. It seems that when the time slicer is running (-ie when I an
running a back ground task but still want the user interface to run),
if I then start another activity using fork, the user interface
occasionally locks up. The background tasks continue to run to
completion and attempt to display their results, but the
ScheduledWindow which is popped up remains blank. It is not until I
type ^C that all returns to normal. It seems that something was
waiting on a Semaphore. The problem seems to be minimised if I fork at
user background priority always. If I fork at userScheduling priority,
then the problem occurs more often.
I know this explanation is probably not too clear but it is quite
complicated. If anyone has a better and more resilient time slicing
mechanism, I would love to hear about it. Perhaps put your solution on
this note.
(This is for Smalltalk Rel4 running on an HP9000/375 work station).
------------------------------------------------------------------------------
Object subclass: #TimeSlicer
instanceVariableNames: 'evaluationBlocks timeSlicerProcess timeSlicerEnabled uiDelay processDelay '
classVariableNames: ''
poolDictionaries: ''
category: 'Time Slicing'!
!TimeSlicer methodsFor: 'time slicing'!
disableTimeSlicing
^timeSlicerEnabled := false.!
enableTimeSlicing
^timeSlicerEnabled := true.!
startTimeSlicer
"Continue to time slice whilst we have blocks to evaluate.
Time slicing is achieved by stopping the user interface for periods of time (uiDelay) and then allowing it
to run again for a period of time (processDelay). The reason we have implemented a time slicer because
it is possible to lock out low priority processes simply by continually moving the mouse. This mechanism
guarantees the user process a proportion of the cpu time."
timeSlicerProcess notNil ifTrue: [^nil].
timeSlicerProcess := [
[(evaluationBlocks isEmpty not) & timeSlicerEnabled]
whileTrue: [
evaluationBlocks do:
[:block |
block notNil
ifTrue: [
block value
ifFalse: [evaluationBlocks remove: block]
ifTrue: [
| ioProcess |
ioProcess := ScheduledControllers activeControllerProcess.
ioProcess suspend.
Cursor execute show.
uiDelay wait.
ioProcess resume.
Cursor normal show.
processDelay wait.]]]].
timeSlicerProcess := nil] forkAt: (Processor userInterruptPriority).!
timeSliceWhile: aBlock
evaluationBlocks add: aBlock.
self startTimeSlicer.! !
!TimeSlicer methodsFor: 'accessing'!
timeSlicerEnabled
^timeSlicerEnabled.!
timeSlicerEnabled: aBoolean
^timeSlicerEnabled := aBoolean.! !
!TimeSlicer methodsFor: 'initialization'!
initialize
evaluationBlocks := OrderedCollection new.
timeSlicerProcess := nil.
timeSlicerEnabled := true.
uiDelay := Delay forMilliseconds: 200.
processDelay := Delay forMilliseconds: 200.! !