package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type Semaphore struct {
acquire chan struct{}
release chan struct{}
}
func NewSemaphore(initialCapacity int) *Semaphore {
s := &Semaphore{
acquire: make(chan struct{}),
release: make(chan struct{}),
}
go s.arbitrator(initialCapacity)
return s
}
func (s *Semaphore) arbitrator(initialCapacity int) {
capacity := initialCapacity
for {
if capacity > 0 {
select {
case s.acquire <- struct{}{}:
capacity--
case <-s.release:
capacity++
}
} else {
<-s.release
capacity++
}
}
}
func (s *Semaphore) Acquire() {
<-s.acquire
}
func (s *Semaphore) Release() {
s.release <- struct{}{}
}
const (
initialPartyCapacity = 5
totalGuests = 15
)
func guest(id int, partyRoom *Semaphore, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Guest %d is trying to enter the party room\n", id)
partyRoom.Acquire()
fmt.Printf("Guest %d has entered the party room\n", id)
// Party for a random duration
partyDuration := time.Duration(rand.Intn(3)+1) * time.Second
time.Sleep(partyDuration)
fmt.Printf("Guest %d is leaving the party room\n", id)
partyRoom.Release()
}
func expandPartyRoom(partyRoom *Semaphore) {
time.Sleep(5 * time.Second) // Wait for 5 seconds before expanding
fmt.Println("Expanding the party room capacity!")
partyRoom.Release()
partyRoom.Release()
}
func main() {
partyRoom := NewSemaphore(initialPartyCapacity)
var wg sync.WaitGroup
// Start the party room expansion routine
go expandPartyRoom(partyRoom)
for i := 0; i < totalGuests; i++ {
wg.Add(1)
go guest(i, partyRoom, &wg)
// Small delay to make output more readable
time.Sleep(100 * time.Millisecond)
}
wg.Wait()
fmt.Println("The party is over!")
}