831059l@aucs.UUCP (Langlois) (12/05/88)
As I mentioned in an earlier posting, I had a few problems getting a small working simulation in Smalltalk/V to work in Smalltalk/V286. Quite simply, the same class and methods that worked in Smalltalk/V didn't work in Smalltalk/V286. The main loop which kept the simulation going in Smalltalk/V was in method proceed in class Simulation was as follows: proceed [eventQueue isEmpty] whileFalse: [currentEntity := eventQueue removeFirst. time := currentEntity time. currentEntity semaphore signal] Looking at this method you might think that I would have to give up the processor at some point in the whileFalse: message to let the entities that are signalled get a change to execute. That is what I thought also when I first implemented the method proceed. I wanted to see what happened if I didn't give up the processor so I removed an expression after the last in the block which sent yield to Processor. In Smalltalk/V it still worked so I permanently removed the expression because, why send it if it doesn't make any difference. In Smalltalk/V286 the Processor must be told to yield the current process for the simulation to work properly, so proceed must be changed as follows: proceed [eventQueue isEmpty] whileFalse: [currentEntity := eventQueue removeFirst. time := currentEntity time. currentEntity semaphore signal. Processor yield] Now, if your curious as to how I found this out, well I executed the simulation under the new V286 debugger and it worked just fine. I tried it again without the debugger and it didn't work. When the debugger steps through the code it must give each process waiting a change to execute, taking in account priority and the amount of time spent waiting, every time it passes control to a process and then interrupts again. In Smalltalk/V when a semaphore is signalled, the processor must be sent the message yield to give the process that was signalled a change to take over the processor. In Smalltalk/V286 this must not be the case, the current process continues to execute until you tell it to give up the processor. The following code also worked fine in Smalltalk/V but caused a debugger window to pop up with the label "value" not understood: probabilityTrue: theProbability theProbability < 0.0 | theProbability > 1.0 ifTrue: [self error: 'Probability must be >= 0.0 and <= 1.0'] ifFalse: [^self new setProbability: theProbability] The or "|" causes problem. In Smalltalk/V286, an instance of class False tries to send the message or: with the argument theProbability which is then sent the message value which is does not understand because it is an instance of class Float = 0.5. Smalltalk/V286 routes the shorthand for "|" through the or: selector while in Smalltalk/V this is not done. or: is implemented as follows: or: aBlock ^aBlock value I inserted a self halt in this message in Smalltalk/V to try and intercept but the self halt was never executed. Smalltalk/V either has different order of evaluation or uses another way to implement "|". By changing the precedence with parentheses as follows, Smalltalk/V286 can execute the method correctly: probabilityTrue: theProbability (theProbability < 0.0) | (theProbability > 1.0) ifTrue: [self error: 'Probability must be >= 0.0 and <= 1.0'] ifFalse: [^self new setProbability: theProbability] In Smalltalk/V the evaluation seems to have the two comparisons execute first and then the result of the second is sent to the first. In Smalltalk/V286 a strict left to right evaluation seems to occur. I read the back of the Smalltalk/V286 manual and under the heading "What is Smalltalk/V 286?" one the items was "Compatibility with Smalltalk/V, the PC version." These are the only differences I have noticed or cared about because they affected my work. Other than the headache of having to find things like this, Smalltalk/V 286 is much better than its predecessor. Steven Langlois UUCP: {uunet|watmath|utai|garfield}!dalcs!aucs!831059l Acadia University BITNET: Steven@Acadia Wolfville, NS Internet: Steven%Acadia.BITNET@CUNYVM.CUNY.EDU CANADA B0P 1X0
831059l@aucs.UUCP (Langlois) (12/06/88)
As so often is the case, one's first interpretation and solution for a problem is not correct. As you'll will shortly see, my mistake was understandable because of the similarity of the output from my simulation. But, nevertheless, it was still a mistake. The simulation is Boats 1 from G. M. Birtwistle's book "Discrete Event Modelling on Simula" (DEMOS). For those unfamaliar, it is a model of a port system with 2 jetties and 3 tugs. The boats, Boat 1, Boat 2, and Boat 3, arrive at times 0.0, 1.0, and 9.7 respectively. The actions of a boat are expressed in a smalltalk method called actions and are as follows: actions self acquire: 1 ofResource: 'JETTIES'. self acquire: 2 ofResource: 'TUGS'. self hold: 2.0. self release: 2 ofResource: 'TUGS'. self hold: 13.9. self acquire: 1 ofResource: 'TUGS'. self hold: 2.0. self release: 1 ofResource: 'TUGS'. self release: 1 ofResource: 'JETTIES' When I put the statement Processor yield in the main loop of my simulation I thought I had solve the problem because with this statement, the simulation run as follows: 0.0 Boat 1 schedules Boat 1 at 0.0 0.0 Boat 2 schedules Boat 2 at 1.0 0.0 Boat 3 schedules Boat 3 at 9.7 0.0 Boat 1 seizes 1 of JETTIES 0.0 Boat 1 seizes 2 of TUGS 0.0 Boat 1 holds for 2.0, until 2.0 1.0 Boat 2 seizes 1 of JETTIES 1.0 Boat 2 awaits 2 of TUGS 2.0 Boat 1 releases 2 to TUGS 2.0 Boat 1 holds for 13.9, until 15.9 9.7 Boat 2 seizes 2 of TUGS 9.7 Boat 2 holds for 2.0, until 11.7 11.7 Boat 2 releases 2 to TUGS 11.7 Boat 2 holds for 13.9, until 25.6 ---------- etc. ------------- The first problem occurs when Boat 1 releases 2 TUGS at 2.0. Boat 2 is waiting for 2 of TUGS and when Boat 1 releases 2 it should seize them and then continue. Instead, Boat 3 arrives and sets the time to 9.7, the time when it was scheduled to arrive. From then on, it's a mess and there is no point of continuing. Now the problem is when the boats are created, they are given the same priority as the process that was created to execute the selected text. So, Boat 3 which has been waiting the longest gets a chance to go before Boat 2 which is waiting for 2 of TUGS. In Smalltalk/V, this wasn't a problem as it seemed that the selected text wasn't a process or it was created with a lower priority than the processes it created. So, in Smalltalk/V the boats where initialized as follows: initialize eventTime := nil. queuedFor := 0. waitingSemaphore := Semaphore new. processOf := [waitingSemaphore wait. self actions] fork In Smalltalk/V286 the boats are given the same priority and hence the problem. To solve the problem, I changed the creation of a boat as follows: initialize eventTime := nil. queuedFor := 0. waitingSemaphore := Semaphore new. processOf := [waitingSemaphore wait. self actions] forkAt: CreationPriority where CreationPriority is a class variable set when a simulation starts to the priority of the initiating Process + 1. Now I'm not so sure I like the solution but it works as shown next: 0.0 Boat 1 schedules Boat 1 at 0.0 0.0 Boat 2 schedules Boat 2 at 1.0 0.0 Boat 3 schedules Boat 3 at 9.7 0.0 Boat 1 seizes 1 of JETTIES 0.0 Boat 1 seizes 2 of TUGS 0.0 Boat 1 holds for 2.0, until 2.0 1.0 Boat 2 seizes 1 of JETTIES 1.0 Boat 2 awaits 2 of TUGS 2.0 Boat 1 releases 2 to TUGS 2.0 Boat 2 seizes 2 of TUGS 2.0 Boat 2 holds for 2.0, until 4.0 2.0 Boat 1 holds for 13.9, until 15.9 4.0 Boat 2 releases 2 to TUGS 4.0 Boat 2 holds for 13.9, until 17.9 9.7 Boat 3 awaits 1 of JETTIES 15.9 Boat 1 seizes 1 of TUGS 15.9 Boat 1 holds for 2.0, until 17.9 17.9 Boat 2 seizes 1 of TUGS 17.9 Boat 2 holds for 2.0, until 19.9 17.9 Boat 1 releases 1 to TUGS 17.9 Boat 1 releases 1 to JETTIES 17.9 Boat 3 seizes 1 of JETTIES 17.9 Boat 3 seizes 2 of TUGS 17.9 Boat 3 holds for 2.0, until 19.9 19.9 Boat 2 releases 1 to TUGS 19.9 Boat 2 releases 1 to JETTIES 19.9 Boat 3 releases 2 to TUGS 19.9 Boat 3 holds for 13.9, until 33.8 33.8 Boat 3 seizes 1 of TUGS 33.8 Boat 3 holds for 2.0, until 35.8 35.8 Boat 3 releases 1 to TUGS 35.8 Boat 3 releases 1 to JETTIES I realize that multliprocessing was added to Smalltalk/V but a Goodies disk but I wish the writers of V 286 would have consulted the creators of the Goodies disk or had of at least inclueded an explanation of the differences somewhere, on disk or in the manual. The is a file showing the differences, but as far as differences in multiprocessing there was nada. Steven Langlois UUCP: {uunet|watmath|utai|garfield}!dalcs!aucs!831059l Acadia University BITNET: Steven@Acadia Wolfville, NS Internet: Steven%Acadia.BITNET@CUNYVM.CUNY.EDU CANADA B0P 1X0
831059l@aucs.UUCP (Langlois) (12/10/88)
Here is an interesting problem. I wanted to create a class Queue
as a subclass of class SortedCollection. An instance of class Queue would
have the sortBlock [ :a : b | a < b ] plus some instance variables such
as observations (to keep track of the number of objects which entered the
queue), maxLength (the maximum length of the queue), etc.
To create a new Queue, I tried the following method:
new
^(self sortBlock: [ :a :b | a < b]) initialize
I then execute the following:
|aQueue|
aQueue := Queue new
I very quickly get a walkback, with the label "stack overflow". I tried this
in Smalltalk/V and it worked fine, in Smalltalk/V286, a different story.
I thought using a selector other than new might help so I tried newQueue, but
not luck. I got the same error.
It took a long time but I finally found the solution to the problem. I defined
class Queue as a variableSubclass of class SortedCollection. That is why (?)
I got the overflow. Just on a whim, I decided to try to define it as a subclass
instead and it worked. In Smalltalk/V, SortedCollection is a variableSubclass
of OrderedCollection. In Smalltalk/V286, it is a subclass of OrderedCollection.
Take a guess at whether it was documented as a change from V to V286!!!
Steven Langlois UUCP: {uunet|watmath|utai|garfield}!dalcs!aucs!831059l
Acadia University BITNET: Steven@Acadia
Wolfville, NS Internet: Steven%Acadia.BITNET@CUNYVM.CUNY.EDU
CANADA B0P 1X0