Process status

Alan Lovejoy sourcery at pacbell.net
Sun Jul 12 19:09:23 UTC 1998



Alexander Lazarevic wrote:

>  > If the shepard process get's terminated without running to completion,
>  > the semaphore will never get signaled, though.
>
> I changed the way the processes get their data. So I don't have to
> check when they have finished. My attempt looks something like
> this
>
> | sq |
> sq := SharedQueue new.
> sq nextPut: 'Nasi'; nextPut: 'Goreng'; nextPut: 'Chop'; nextPut: 'Suey'.
> 1 to: 2 do: [:pid|
>    [[sq isEmpty] whileFalse: [Transcript show: sq next; cr. Processor yield]] fork].
>
> Now I want to see, which process outputs the data. So my first try
> was:
>
> Transcript show: pid printString, ' ', sq next
>
> That won't work, because after the loop pid is 3 and all processes
> return that value. So how do I create a variable, that is local to a
> block? Something like [:pid| blockTemp | blockTemp := pid ] won't work
> either.

Try this:

    1 to: 2 do: [:pid | [Transcript cr; show: pid printString] fixTemps; fork]

In fact, you can create a "BlockClosure" class that wraps a BlockContext.
Whenever a new BlockContext is assigned to the enclosing BlockClosure,
send  #fixTemps to the BlockContext. Adding #asClosure to BlockContext
makes this relatively convenient to use.

Example:

Object subclass: #BlockClosure
    instanceVariableNamess: 'block'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Kernel-Methods'!

!BlockClosure methodsFor: 'initialize-release'!

block: aBlock
    block := aBlock valueForClosure!

!BlockClosure methodsFor: 'accessing'!

valueForClosure
    ^block valueForClosure! !

!BlockClosure methodsFor: 'evaluating'! !

value
    ^block value!

value: anArg
    ^block value: anArg!

value: arg1 value: arg2
    ^block value: arg1 value: arg2!

value: arg1 value: arg2 value: arg3
    ^block value: arg1 value: arg2 value: arg3!

valueWithArguments: argArray
    ^block valueWithArguments: argArray! !

!BlockClosure methodsFor: 'scheduling'!

fork
    ^block fork! !

!BlockClosure class methodsFor: 'instance creation'!

block: aBlock
    ^self new block: aBlock! !

!BlockContext methodsFor: 'converting'!

asClosure
    ^BlockClosure block: self! !

!BlockContext methodsFor: 'accessing'!

valueForClosure
    ^self  fixTemps! !

| closure |
closure := [:pid | [Transcript cr; show: pid printString] fork] asClosure.
1 to: 2 do: closure.

As you can see, this implementation adds some overhead, which is why it is
best done at the VM level.

And the implementation above does not make blocks reentrant, unlike the
BlockClosures in VisualWorks (for example).

To make the BlockClosures reentrant, it is necessary to do a few extra things:

    * the method BlockContext>valueForClosure must answer
      << ^self copy reset; fixTemps >> so that the program counter of the block
      stored in the closure will be at the beginning
    * the evaluating methods in BlockClosure must all use a copy of the block
       stored in the closure's instance variable, so the  method
       BlockClosure>value: anArg would (for example)  have to look like this:

BlockClosure>value: anArg
    ^block copy value: anArg

--Alan





More information about the Squeak-dev mailing list