Archive

Posts Tagged ‘Scheduling’

GPARS Actors and sleeping barber example

November 27, 2014 Leave a comment

started to look at the GPARS library and how to apply this into my programms – found an earlier example from Hamlet D’arcy, but it was out of date relative to latest GPARs constructs, and scheduling work at particular times

So i’ve had a go at relaunching it in new clothes. In order to simulate the waiting room i’ve used blocking queue of fixed size. Adding a customer will block when the waiting room is full – until someone (the barber takes one as his next customer)like this by sending a message to the actor

     barber << check client  //message to actor

in the second approach i've used the timer service to repeatedly schedule a message to a second barber ( not an actor ) which runs the action takes a client and reschedules itself for next ask

def barber2 = Executors.newScheduledThreadPool(1)
barber2.scheduleAtFixedRate({
	     println 'Barber2: Next customer please!'
		 Customer customer = waitingRoom.take()
		 println "${customer.name} gets a haircut at ${new Date().format('H:m:s')}" }
 as Runnable, 0, 5, TimeUnit.SECONDS)

the complete groovy script solution looks like this

package com.softwood.script

import groovy.transform.Immutable
import groovyx.gpars.group.DefaultPGroup

import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit


// create waiting room can't hold more than 12!  array queue of customers
def waitingRoom = new ArrayBlockingQueue(12)

/**
 * ArrayBlockingQueue filled with customers that need a haircut. 
 * And the barber is an executor service with a scheduled task to 
 * give haircuts. The number of threads in the scheduled thread 
 * pool is 1 because there's only one barber. The barber takes 
 * customers from the waiting room and cuts their hair once every 
 * 15 minutes. The call to waitingRoom.take() is blocking... if 
 * there is a customer ready then he is serviced immediately, and 
 * if one is not, then the call blocks until someone is available. 
 * Once thing to note... the waitingRoom has a size of 12... if a 
 * 13th customer is added then the calling code will either block 
 * until there is enough room or throw an exception. There is an 
 * API to do either case.
 */
final def group = new DefaultPGroup ()

//event driven actor model 
final def barberShop = group.reactor {message ->
	switch (message) {
		case Enter :
			println "${message.customer.name} enters and is waiting for a haircut"
			//add customer from message to the waiting room 
			waitingRoom.add (message.customer)
			break
		
		case "quit":
			println "called quit on barbershop - now new customers can come in"
			terminate()
			break
		
	}
}

// message to post on barberShop
@Immutable
class Enter {
	Customer customer
}

//customer for barbershop
@Immutable
class Customer {
	String name
}

//create a single barber - thread pool size of 1
final DefaultPGroup barberGroup = new DefaultPGroup (1)


println "barber opening shop"
//this model auto starts the barber
final barber = barberGroup.actor {
	loop {
		react {
			println "barber> asked to -> $it"
			println "barber> Next Customer Please!"
			Customer customer = waitingRoom.take()  //blocking call on waiting room
			println "barber> ${customer.name} gets a haircut at ${new Date().format('H:m:s')}"
		}
	}
}

def barber2 = Executors.newScheduledThreadPool(1)
barber2.scheduleAtFixedRate({
	     println 'Barber2: Next customer please!'
		 Customer customer = waitingRoom.take()
		 println "${customer.name} gets a haircut at ${new Date().format('H:m:s')}" }
 as Runnable, 0, 5, TimeUnit.SECONDS)


//add some customers to waiting room 
barberShop << new Enter(customer: new Customer(name: 'Jerry'))
barberShop << new Enter(customer: new Customer(name: 'Phil'))
barberShop << new Enter(customer: new Customer(name: 'Bob'))
barberShop << new Enter(customer: new Customer(name: 'Ron'))
barberShop << "quit"

//send 'message' to first barber 
barber << "check client  "

//barber.stop()
barber.join (20, TimeUnit.SECONDS)
println "customers in queue ${waitingRoom.size()}"
println "barber closing shop"

i’ve used @ immutable to construct a a thread safe message with thread safe ‘customer’ to pass to the waiting room

Advertisements
Categories: GPARS, Groovy Tags: , , ,
%d bloggers like this: