Yes, that is a very clever solution. You could tidy this up a little by using:
Array subclass: #YieldingArray instanceVariableNames:'' classVariableNames: '' poolDictionaries: '' category: 'Temp'
YieldingArray>>do: aBlock "Evaluate aBlock with all the arguments. Yield in the middle." 1 to: self size do:[:i| aBlock value: i. Processor yield. ].
#yield will take care of things without a semaphore due to Squeak's process scheduling rules.
Cheers, - Andreas
Martin v. Löwis wrote:
queue := self newQueue. writingBlock := [queue nextPutAll: (1 to: 10000)]. writingBlock fork; fork; fork. Processor yield. self assert: (queue next: 10000) asArray = (1 to: 10000) asArray. self assert: (queue next: 10000) asArray = (1 to: 10000) asArray. self assert: (queue next: 10000) asArray = (1 to: 10000) asArray. self assert: queue atEnd.
I assume it's because when I fork, the work is done before the following fork starts.
Can somebody help me writing this test?
I assume that nextPutAll: relies on do: to fetch all elements of the collection. So you could define a BlockingCollection, which contains a collection, and a semaphore as instance variables. Then, do: would do
do: aBlock collection do:[:each| semaphore wait. aBlock value: each. semaphore signal. ].
Alternatively, if it relies on at: also implement
at: index | result | semaphore wait. result := collection at: index. semaphore signal. ^result.
Then, in the test, you do
sem := Semaphore new. writingBlock := [queue nextPutAll: (BlockingCollection on: (1 to: 10000) with: sem)]. sem signal.
HTH, Martin