6.2 The first known correct software solution to the critical-section problem for $n$ processes with a lower bound on waiting of $n − 1$ turns was presented by Eisenberg and McGuire. The processes share the following variables:

enum pstate { idle, want_in, in_cs };
pstate flag[n];
int turn;


All the elements of flag are initially idle; the initial value of turn is immaterial (between 0 and n-1 ). The structure of process $P_i$ is shown in Figure 6.26. Prove that the algorithm satisfies all three requirements for the critical-section problem.

6.11 The Sleeping-Barber Problem. A barbershop consists of a waiting room with 11 chairs and a barber room with one barber chair. If there are no customers to be served, the barber goes to sleep. If a customer enters the barbershop and all chairs are occupied, then the customer leaves the shop. If the barber is busy but chairs are available, then the customer sits in one of the free chairs. If the barber is asleep, the customer wakes up the barber. Write a program to coordinate the barber and the customers.

package main

import (
"fmt"
"math/rand"
"os"
"os/signal"
"strconv"
"syscall"
"time"
)

// const chairNum = 11

var charAvailable = 11
var wakeup = 0

func main() {
rand.Seed(time.Now().Unix())
go spawnBarber()
go spawnCustomer()
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
os.Exit(0)
}

var totalNum = 1000
var maxSpawnDur = 100 // 1000 = 1sec

func spawnCustomer() {
for i := 0; i < totalNum; i++ {
var spawnDur = time.Duration((rand.Intn(maxSpawnDur)) * 10e+5)
time.Sleep(spawnDur)
for j := 0; j < 10; j++ {
go (func() {
var id = j*10 + i
fmt.Println("Customer " + strconv.Itoa(id) + " comes")
if charAvailable == 0 {
fmt.Printf("Customer %v angrily gone for no chair (available = %v) \n", id, charAvailable)
return
}
if charAvailable < 0 {
panic(fmt.Sprintf("Your program has bug! charAvailable = %v", charAvailable))
}

if wakeup != 0 && wakeup != 1 {
panic(fmt.Sprintf("Your program has bug! wakeup = %v", wakeup))
}

for wakeup == 1 {
time.Sleep(1 * time.Microsecond)
}

charAvailable--
wakeup++
charAvailable++
fmt.Printf("Customer %v happily gone (available = %v) \n", id, charAvailable)

})()
}
}
}

func spawnBarber() {
for {
for wakeup == 0 {
time.Sleep(1 * time.Microsecond)
}
fmt.Printf("Barber woke up. wakeup = %v \n", wakeup)
var workDur = time.Duration((rand.Intn(maxSpawnDur)) * 2 * 10e+5)
time.Sleep(workDur)
fmt.Printf("Barber sleep down. wakeup = %v \n", wakeup)
wakeup--
}
}



Customer 178 comes
Customer 179 comes
Customer 189 comes
Customer 184 comes
Customer 186 comes
Customer 180 comes
Customer 185 comes
Customer 187 comes
Customer 183 comes
Customer 188 comes
Customer 181 comes
Customer 182 comes
Barber sleep down. wakeup = 1
Customer 187 happily gone (available = 9)
panic: Your program has bug! charAvailable = -2

goroutine 140 [running]:
main.spawnCustomer.func1()
C:/Repo/Sleeping-Barber-Problem/main.go:67 +0x294
created by main.spawnCustomer
C:/Repo/Sleeping-Barber-Problem/main.go:43 +0x9c
panic: Your program has bug! charAvailable = -4


				if charAvailable < 0 {
panic(fmt.Sprintf("Your program has bug! charAvailable = %v", charAvailable))
}

if wakeup != 0 && wakeup != 1 {
panic(fmt.Sprintf("Your program has bug! wakeup = %v", wakeup))
}



package main

import (
"fmt"
"math/rand"
"os"
"os/signal"
"strconv"
"sync"
"syscall"
"time"
)

// const chairNum = 11

var charAvailable = 11
var wakeup = 0

func main() {
rand.Seed(time.Now().Unix())
go spawnBarber()
go spawnCustomer()
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
os.Exit(0)
}

var mu sync.Mutex
var muId sync.Mutex

var totalNum = 1000
var maxSpawnDur = 100 // 1000 = 1sec

func spawnCustomer() {
for i := 0; i < totalNum; i++ {
var spawnDur = time.Duration((rand.Intn(maxSpawnDur)) * 10e+5)
time.Sleep(spawnDur)
for j := 0; j < 10; j++ {
muId.Lock()
var id = i*10 + j
muId.Unlock()
go (func() {
fmt.Println("Customer " + strconv.Itoa(id) + " comes")
if charAvailable == 0 {
fmt.Printf("Customer %v angrily gone for no chair (available = %v) \n", id, charAvailable)
return
}
if charAvailable < 0 {
panic(fmt.Sprintf("Your program has bug! charAvailable = %v", charAvailable))
}

if wakeup != 0 && wakeup != 1 {
panic(fmt.Sprintf("Your program has bug! wakeup = %v", wakeup))
}

for wakeup == 1 {
time.Sleep (1 * time.Microsecond) // 等待理发机会
}
mu.Lock()
charAvailable--
wakeup++
for wakeup == 1 {
time.Sleep (1 * time.Microsecond) // 等待理发完成
}
mu.Unlock()
if charAvailable < 0 {
panic(fmt.Sprintf("Your program has bug! charAvailable = %v", charAvailable))
}

fmt.Printf("Customer %v happily gone (available = %v) \n", id, charAvailable)

})()
}
}
}

func spawnBarber() {
for {
for wakeup == 0 {
time.Sleep(1 * time.Microsecond)
}
fmt.Printf("Barber woke up. wakeup = %v \n", wakeup)
var workDur = time.Duration((rand.Intn(maxSpawnDur)) * 2 * 10e+5)
time.Sleep(workDur)
fmt.Printf("Barber sleep down. wakeup = %v \n", wakeup)
wakeup--
charAvailable++
}
}