Next problem in line in the the little Go book of semaphores series is about caring for children. It comes from the book “Operating Systems and Middleware: Supporting Controlled Interaction” by Max Hailperin (problem 4.6). It reads as follows:

State licensing rules require a child-care center to have no more than three infants present for each adult

To put it in a different way: there’s a room where both adults and children are found. For a children to enter the room, an adult must be already there. At that point up to two more children can enter. A fourth children has to wait for another adult to appear. Same goes when an adult wants to leave: if the number of adults present in the room is n, after one leaves it’s n-1 and therefore the number of children left in the room must be equal or less than 3*(n-1). While there are more children than that, the adult cannot leave.

If you have been reading the series, you already know where this is going: children enter using a channel cIn and adults use a channel aIn. A select switches between the actual cIn channel and nil according to the number of adults present. When they want to leave, they use a cOut and aOut channels. The select statement switches between the actual aOut channel and a nil channel to prevent adults from leaving when there are too many children.

In code:

	select {
	case <-c.aIn:
		nAdults++
	case <-aOut:
		nAdults--
	case <-cIn:
		nChildren++
	case <-c.cOut:
		nChildren--
	}

	if 3*nAdults > nChildren {
		// children can enter
		cIn = c.cIn
	} else {
		// don't let more children in
		cIn = nil
	}

	if 3*(nAdults-1) > nChildren {
		// adults can leave
		aOut = c.aOut
	} else {
		// don't let adults out
		aOut = nil
	}

There are two conditions here. The first one is that there must be enough adults already in the room for children to enter and the state licensing rules to be followed. The second one is that there must be enough adults in the room such that if one of them leaves, the remaining adults in the room are still enough to watch over the children according to the rules.

Adults and children are modelled as gorotines. Each goroutine uses the corresponding channel to “enter” the child care center and each uses the corresponding channel to exit it. For example, the adult goroutines look like this:

	go func() {
		a := Adult{Name: fmt.Sprintf("Adult %d", i)}
		c.aIn <- a
		time.Sleep(randMillisecond(5*N, 7*N))
		c.aOut <- a
	}()

This solution, which I believe solves the problem as stated, happens to be the solution to what the author calls the “extended child care problem”. For the extended version, consider the sitaution where there are 4 children and 2 adults in the center. Within the rules, the center can accept up to 6 children in this case. In the author’s solution to the basic problem, the leaving adult takes away two of the slots and blocks waiting for a child to leave. If another child arrives at the center in this situation, it will block trying to enter because the leaving adult already took away the two free slots it was providing. In the extended version, the arriving child does not block and the adult is now blocking waiting for two children to leave.

The full source (with minor modifications for presentation) is here.

Next week, the dean gets to break up student parties.