Looking for Monitor example

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

Looking for Monitor example

Chris Muller
Has anyone used the heavyweight (Mesa) Monitor?  I want to try the conditional waiting, but keep getting a 'Monitor access violation'.  I think its actually a bug in the code; its signaling code is performing #checkOwnerProcess, but this should only be done by the 'wait' code (which it is).
 
 The disconcerting part of this is; I don't see how Monitor can work at all this way.  There is no test case in the 3.8 image and I've found no example usages which could help prove me wrong.
 
 I wrote a test case demonstrating how I think it can be used.  Running the test results in a Monitor access violation.  But if I remove the call to #checkOwnerProcess in the signal method (my proposed fix) the test works fine.
 
 So, does anyone have any experience with the heavyweight (Mesa) Monitor and how did it work for you?  Does this test represent misuse or is there really an issue with Monitor?
 
 testConditionalWaits
     "Start two background processes that build an OrderedCollection with the numbers 1 to 1000.  The 'fives' process will only add numbers modulo 5 = 0 (i.e., 5, 10, 15, 20, ...) whereas the 'nonFives' process adds all the others.  A third monitor waits until the goal is reached before asserting the goal was reached successfully."
     | goal work fives nonFives counter goalReached goalMonitor |
     goal _ (1 to: 1000) asOrderedCollection.
     work _ OrderedCollection new.
     fives _ Monitor new.
     nonFives _ Monitor new.
     counter _ 0.
     goalReached _ false.
     goalMonitor _ Monitor new.
     [ fives critical:
         [ [ fives waitUntil: [ counter \\ 5 = 0 ].
         goalReached or:
             [ work add: (counter _ counter+1).
             nonFives signal.
             goalReached _ counter >= goal size ] ] whileFalse.
         goalMonitor signal ] ] fork.
     [ nonFives critical:
         [ [ nonFives waitWhile: [ counter \\ 5 = 0 ].
         goalReached or:
             [ work add: (counter _ counter+1).
             fives signal.
             goalReached _ counter >= goal size ] ] whileFalse.
         goalMonitor signal ] ] fork.
     goalMonitor critical:
         [ goalMonitor waitUntil: [ goalReached ].
         self assert: goal = work ]
 
 Thanks..
 


Reply | Threaded
Open this post in threaded view
|

Re: Looking for Monitor example

Boris.Gaertner


Hello,

Attached you find the relevant page from my MVC Tutorial that contains
four versions of a producer/consumer example.


The comment of the Monitor class says that you can signal only from
within the critical section of a monitor.
It is therefore not allowed to write:

  monitor1 critical: ["  do something "
                              monitor2 signal ].

The following examples demonstrate that you can (and should) use
one single monitor to do all synchronization. (This is the essential
difference
to semaphores. When you synchronize processes with semaphores,
you will usually need more than one sema.)

And here is a working version of your example. You can try
it immediately in a workspace (with 'inspect').

 | producer1 producer2  monitor goal work counter goalReached finished |
     goal _ (1 to: 1000) asOrderedCollection.
     work _ OrderedCollection new.
     counter := 0.
     goalReached := false.
     finished := Semaphore new.
 monitor := Monitor new.

  producer1 :=
      [
       [monitor critical:
             [monitor waitUntil: [counter \\5 = 0].
              goalReached or: [work add: (counter := counter + 1)].
              goalReached := counter >= goal size.
              monitor signal
            ].
           goalReached
          ]
             whileFalse.
         finished signal.
 ] .

 producer2 :=
     [
         [monitor critical:
                [monitor waitWhile: [counter \\5 = 0].
                 goalReached or: [work add: (counter := counter + 1)].
                 goalReached := counter >= goal size.
                 monitor signal
               ].
         goalReached
       ]
             whileFalse.
     finished signal
   ] .

producer1 forkAt: Processor userBackgroundPriority.
producer2  forkAt: Processor userBackgroundPriority.


 finished wait; wait.

goal = work.



----------------------------------------------------------------


Here is a second version that does not use a semaphore to inform the
forking process about termination of both forked processes:


 | producer1 producer2  monitor goal work counter goalReached
  activeProducers|
     goal _ (1 to: 1000) asOrderedCollection.
     work _ OrderedCollection new.
     counter := 0.
     goalReached := false.
     activeProducers := 0.
 monitor := Monitor new.

  producer1 :=
      [ monitor critical: [activeProducers := activeProducers + 1].
  [monitor critical:
            [monitor waitUntil: [counter \\5 = 0].
      goalReached or: [work add: (counter := counter + 1)].
     " Transcript show: 'P1  '; show: counter printString; show: '  ';
       show: activeProducers printString; cr."
      goalReached := counter >= goal size.
      monitor signal
            ].
           goalReached
          ]
             whileFalse.
         monitor critical: [activeProducers := activeProducers - 1.
        monitor signal: #finish].
 ] .

 producer2 :=
    [monitor critical: [activeProducers := activeProducers + 1].

  [monitor critical:
          [monitor waitWhile: [counter \\5 = 0].
    goalReached or: [work add: (counter := counter + 1)].
     "Transcript show: 'P2  '; show: counter printString; show: '  ';
                 show: activeProducers printString; cr."
    goalReached := counter >= goal size.
    monitor signal
          ].
         goalReached
       ]
             whileFalse.
     monitor critical: [activeProducers := activeProducers - 1.
          monitor signal: #finish].

   ] .

producer1 forkAt: Processor userBackgroundPriority.
producer2  forkAt: Processor userBackgroundPriority.


 monitor critical:
  [monitor waitUntil: [" Transcript show: 'Test finish cond'; show:
activeProducers printString; cr. "
                                activeProducers = 0 & (goalReached)]
           for: #finish.
  ].

goal = work


-------------

Hope this helps.
Boris



Monitor.zip (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Looking for Monitor example, addendum

Boris.Gaertner
In reply to this post by Chris Muller
Hello again, Chris,

your example is not that bad; your only mistake is that you signal
a foreign monitor without entering its critical region.

You have to replace     goalMonitor signal.
with:   goalMonitor critical: [goalMonitor signal].

and in the same way

  fives signal.   with:    fives critical: [fives signal].
 nonFives signal.  with:  nonFives critical: [nonFives signal].

The following works:

     | goal work fives nonFives counter goalReached goalMonitor |
     goal _ (1 to: 1000) asOrderedCollection.
     work _ OrderedCollection new.
     fives _ Monitor new.
     nonFives _ Monitor new.
     counter _ 0.
     goalReached _ false.
     goalMonitor _ Monitor new.

     [ fives critical:
         [ [ fives waitUntil: [ counter \\ 5 = 0 ].
         goalReached or:
             [ work add: (counter _ counter+1).
             nonFives critical: [nonFives signal].
             goalReached _ counter >= goal size ] ] whileFalse.
         goalMonitor critical: [goalMonitor signal] ] ] fork.

     [ nonFives critical:
         [ [ nonFives waitWhile: [ counter \\ 5 = 0 ].
         goalReached or:
             [ work add: (counter _ counter+1).
             fives critical: [fives signal].
             goalReached _ counter >= goal size ] ] whileFalse.
         goalMonitor critical: [goalMonitor signal] ] ] fork.

     goalMonitor critical:
         [ goalMonitor waitUntil: [ goalReached ].
        ].

  work = goal


-----------------------

Note that the process 'fives' adds the seqeuence 1, 6, 11 into your
collection. To fix that, both processes should use the wait condition
 [ counter \\5 = 4].
Alternatively, the counter could start at 1 and be incremented after
insertion into the collection. The correct expression for  goalReached
would then be:  counter > goal size.


Greetings, Boris

Reply | Threaded
Open this post in threaded view
|

Re: Looking for Monitor example

Chris Muller-2
In reply to this post by Chris Muller
That sure does clear it up for me.  I now appreciate how this #checkOwnerProcess helps ensure proper usage..
 
 Thanks Boris.
 
  - Chris
 

----- Original Message ----
From: Boris Gaertner <[hidden email]>
To: The general-purpose Squeak developers list <[hidden email]>
Sent: Sunday, March 19, 2006 5:08:54 AM
Subject: Re: Looking for Monitor example



Hello,

Attached you find the relevant page from my MVC Tutorial that contains
four versions of a producer/consumer example.


The comment of the Monitor class says that you can signal only from
within the critical section of a monitor.
It is therefore not allowed to write:

  monitor1 critical: ["  do something "
                              monitor2 signal ].

The following examples demonstrate that you can (and should) use
one single monitor to do all synchronization. (This is the essential
difference
to semaphores. When you synchronize processes with semaphores,
you will usually need more than one sema.)

And here is a working version of your example. You can try
it immediately in a workspace (with 'inspect').

 | producer1 producer2  monitor goal work counter goalReached finished |
     goal _ (1 to: 1000) asOrderedCollection.
     work _ OrderedCollection new.
     counter := 0.
     goalReached := false.
     finished := Semaphore new.
 monitor := Monitor new.

  producer1 :=
      [
       [monitor critical:
             [monitor waitUntil: [counter \\5 = 0].
              goalReached or: [work add: (counter := counter + 1)].
              goalReached := counter >= goal size.
              monitor signal
            ].
           goalReached
          ]
             whileFalse.
         finished signal.
 ] .

 producer2 :=
     [
         [monitor critical:
                [monitor waitWhile: [counter \\5 = 0].
                 goalReached or: [work add: (counter := counter + 1)].
                 goalReached := counter >= goal size.
                 monitor signal
               ].
         goalReached
       ]
             whileFalse.
     finished signal
   ] .

producer1 forkAt: Processor userBackgroundPriority.
producer2  forkAt: Processor userBackgroundPriority.


 finished wait; wait.

goal = work.



----------------------------------------------------------------


Here is a second version that does not use a semaphore to inform the
forking process about termination of both forked processes:


 | producer1 producer2  monitor goal work counter goalReached
  activeProducers|
     goal _ (1 to: 1000) asOrderedCollection.
     work _ OrderedCollection new.
     counter := 0.
     goalReached := false.
     activeProducers := 0.
 monitor := Monitor new.

  producer1 :=
      [ monitor critical: [activeProducers := activeProducers + 1].
  [monitor critical:
            [monitor waitUntil: [counter \\5 = 0].
      goalReached or: [work add: (counter := counter + 1)].
     " Transcript show: 'P1  '; show: counter printString; show: '  ';
       show: activeProducers printString; cr."
      goalReached := counter >= goal size.
      monitor signal
            ].
           goalReached
          ]
             whileFalse.
         monitor critical: [activeProducers := activeProducers - 1.
        monitor signal: #finish].
 ] .

 producer2 :=
    [monitor critical: [activeProducers := activeProducers + 1].

  [monitor critical:
          [monitor waitWhile: [counter \\5 = 0].
    goalReached or: [work add: (counter := counter + 1)].
     "Transcript show: 'P2  '; show: counter printString; show: '  ';
                 show: activeProducers printString; cr."
    goalReached := counter >= goal size.
    monitor signal
          ].
         goalReached
       ]
             whileFalse.
     monitor critical: [activeProducers := activeProducers - 1.
          monitor signal: #finish].

   ] .

producer1 forkAt: Processor userBackgroundPriority.
producer2  forkAt: Processor userBackgroundPriority.


 monitor critical:
  [monitor waitUntil: [" Transcript show: 'Test finish cond'; show:
activeProducers printString; cr. "
                                activeProducers = 0 & (goalReached)]
           for: #finish.
  ].

goal = work


-------------

Hope this helps.
Boris