[squeak-dev] Process conflict when redisplaying World

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Process conflict when redisplaying World

Trygve
Image is Squeak3.10.gamma.7159.

I have a visualization demo. It runs in a separate process to permit mouse and keyboard input while it runs:
    startChaosAnimation
        currentState = #CHAOS ifTrue: [^self].
        currentState := #CHAOS.
        processSemaphore wait.
            BB2ChaosCtx startChaosAnimationOn: data.
            processSemaphore signal.
        ] fork.

BB2ChaosCtx startChaosAnimationOn: data starts a loop that creates and removes Morphs interspersed with suitable Delays to get the speed right.

The process can run for several hours before crashing in various ways. It sometimes crashes with a primitiveError while redisplaying World. A simpler stop was an MNU in
    MorphicEventDispatcher>>dispatchDefault: anEvent with: aMorph
where aMorph =  a PasteUpMorph [world], with fullBounds = nil

My process is clearly in some unfortunate state when the main process repaints or handles the mouse. Any ideas how I should make my process safe?

Thanks in advance
--Trygve


--
--

Trygve Reenskaug       mailto: [hidden email]

Morgedalsvn. 5A         http://heim.ifi.uio.no/~trygver

N-0378 Oslo               Tel: (+47) 22 49 57 27

Norway



Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: Process conflict when redisplaying World

Andreas.Raab
Trygve Reenskaug wrote:

> I have a visualization demo. It runs in a separate process to permit
> mouse and keyboard input while it runs:
>     startChaosAnimation
>         currentState = #CHAOS ifTrue: [^self].
>         currentState := #CHAOS.
>         processSemaphore wait.
>             BB2ChaosCtx startChaosAnimationOn: data.
>             processSemaphore signal.
>         ] fork.
>
> BB2ChaosCtx startChaosAnimationOn: data starts a loop that creates and
> removes Morphs interspersed with suitable Delays to get the speed right.
>
> The process can run for several hours before crashing in various ways.
> It sometimes crashes with a primitiveError while redisplaying World. A
> simpler stop was an MNU in
>     MorphicEventDispatcher>>dispatchDefault: anEvent with: aMorph
> where aMorph =  a PasteUpMorph [world], with fullBounds = nil
>
> My process is clearly in some unfortunate state when the main process
> repaints or handles the mouse. Any ideas how I should make my process safe?

Use Morph stepping instead of an unsynchronized process.

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: Process conflict when redisplaying World

Trygve
Thanks Andreas, for your very quick answer.
Stepping was the first mechanism I tried, but the program got very complex keeping track of what to do at each step. My goal is to have a simple, readable program and the stepping alternative was neither simple nor readable.  So I'm trying other solutions.

Cheers
--Trygve

On 06.05.2009 18:09, Andreas Raab wrote:
Trygve Reenskaug wrote:
I have a visualization demo. It runs in a separate process to permit mouse and keyboard input while it runs:
    startChaosAnimation
        currentState = #CHAOS ifTrue: [^self].
        currentState := #CHAOS.
        processSemaphore wait.
            BB2ChaosCtx startChaosAnimationOn: data.
            processSemaphore signal.
        ] fork.

BB2ChaosCtx startChaosAnimationOn: data starts a loop that creates and removes Morphs interspersed with suitable Delays to get the speed right.

The process can run for several hours before crashing in various ways. It sometimes crashes with a primitiveError while redisplaying World. A simpler stop was an MNU in
    MorphicEventDispatcher>>dispatchDefault: anEvent with: aMorph
where aMorph =  a PasteUpMorph [world], with fullBounds = nil

My process is clearly in some unfortunate state when the main process repaints or handles the mouse. Any ideas how I should make my process safe?

Use Morph stepping instead of an unsynchronized process.

Cheers,
  - Andreas



--
--

Trygve Reenskaug       mailto: [hidden email]

Morgedalsvn. 5A         http://heim.ifi.uio.no/~trygver

N-0378 Oslo               Tel: (+47) 22 49 57 27

Norway



Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: Process conflict when redisplaying World

Andreas.Raab
Trygve Reenskaug wrote:
> Thanks Andreas, for your very quick answer.
> Stepping was the first mechanism I tried, but the program got very
> complex keeping track of what to do at each step. My goal is to have a
> simple, readable program and the stepping alternative was neither simple
> nor readable.  So I'm trying other solutions.

In that case you need to define what a "stable" state for your
simulation is. Once you have that you can implement something where you
pass a semaphore into the simulation that is being signaled when the
simulation should make progress, and that the simulation waits on when
it's in a stable state. Along the lines of:

sema := Semaphore new.
[
   sema wait. "wait for the simulation to begin"
   simulator syncSema: sema.
   simulator simulate.
] forkAt: Processor userInterruptPriority.

MyMorph>>step
   "Allow our simulation to run until it has reached stable state"
   sema signal.

Then anywhere in the simulation where it's safe to do so, just throw in
a sema wait.

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Process conflict when redisplaying World

David T. Lewis
In reply to this post by Trygve
On Wed, May 06, 2009 at 05:50:09PM +0200, Trygve Reenskaug wrote:

> Image is Squeak3.10.gamma.7159.
>
> I have a visualization demo. It runs in a separate process to permit
> mouse and keyboard input while it runs:
>    startChaosAnimation
>        currentState = #CHAOS ifTrue: [^self].
>        currentState := #CHAOS.
>        processSemaphore wait.
>            BB2ChaosCtx startChaosAnimationOn: data.
>            processSemaphore signal.
>        ] fork.
>
> BB2ChaosCtx startChaosAnimationOn: data starts a loop that creates and
> removes Morphs interspersed with suitable Delays to get the speed right.
>
> The process can run for several hours before crashing in various ways.
> It sometimes crashes with a primitiveError while redisplaying World. A
> simpler stop was an MNU in
>    MorphicEventDispatcher>>dispatchDefault: anEvent with: aMorph
> where aMorph =  a PasteUpMorph [world], with fullBounds = nil
>
> My process is clearly in some unfortunate state when the main process
> repaints or handles the mouse. Any ideas how I should make my process safe?

Morphic does everything in its own main UI process, but none of the things
that happen in that process are necessarily "thread safe". If you want some
other process (such as the process in which your animation is running) to do
things in the Morphic UI process, then your animation process should schedule
things to be executed:

  WorldState addDeferredUIMessage: [doSomethingInTheMorphicUIProcess]

This causes #doSomethingInTheMorphicUIProcess to be evaluated shortly
thereafter in the context of the Morphic UI process, hence no crashes.

I have not tried this with MorphicEventDispatcher>>dispatchDefault:with:,
but I expect that wrapping the call in #addDeferredUIMessage: may take
care of your problem.

Dave


Reply | Threaded
Open this post in threaded view
|

Important Morphic discovery. (was Re: [squeak-dev] Process conflict when redisplaying World)

Trygve
In reply to this post by Andreas.Raab
Hi Andreas,
Many thanks for helping me along. Your advice to use stepping was sound, but didn't quite fit my needs. I tried several alternative solutions with running my visualization in a separate process, but they all failed.

This led to an important (in retrospect: obvious) discovery:

I CANNOT CHANGE THE DISPLAYED MORPHS IN A SEPARATE PROCESS.
Reason: Adding, removing, or changing a submorph lead to a call on Morph>>layoutChanged which sets fullBounds := nil recursively up the owner chain.

At the same time, the normal process is happily repeating WorldState>>doOneCycleFor: aWorld. This includes redisplaying the World, computing fullBounds if needed.

The separate process can have set fullBounds to nil at any point in the redisplay loop. Usually, this has no bad effect, but MNU or primitiveError can happen in rare cases. (I run my animation overnight to make this happen.) Hence the above conclusion. Two unsynchronized processes should not share a common variable. The basic process and my process did share the whole morphic display hierarchy.

No apologies for stating the obvious
--Trygve



On 06.05.2009 18:09, Andreas Raab wrote:
Trygve Reenskaug wrote:
I have a visualization demo. It runs in a separate process to permit mouse and keyboard input while it runs:
    startChaosAnimation
        currentState = #CHAOS ifTrue: [^self].
        currentState := #CHAOS.
        processSemaphore wait.
            BB2ChaosCtx startChaosAnimationOn: data.
            processSemaphore signal.
        ] fork.

BB2ChaosCtx startChaosAnimationOn: data starts a loop that creates and removes Morphs interspersed with suitable Delays to get the speed right.

The process can run for several hours before crashing in various ways. It sometimes crashes with a primitiveError while redisplaying World. A simpler stop was an MNU in
    MorphicEventDispatcher>>dispatchDefault: anEvent with: aMorph
where aMorph =  a PasteUpMorph [world], with fullBounds = nil

My process is clearly in some unfortunate state when the main process repaints or handles the mouse. Any ideas how I should make my process safe?

Use Morph stepping instead of an unsynchronized process.

Cheers,
  - Andreas



--
--

Trygve Reenskaug       mailto: [hidden email]

Morgedalsvn. 5A         http://heim.ifi.uio.no/~trygver

N-0378 Oslo               Tel: (+47) 22 49 57 27

Norway