Skip to content

Instantly share code, notes, and snippets.

@tebeka
Created May 8, 2024 14:35
Show Gist options
  • Save tebeka/3fd798272ed1377a8427954181fd4a1d to your computer and use it in GitHub Desktop.
Save tebeka/3fd798272ed1377a8427954181fd4a1d to your computer and use it in GitHub Desktop.
Semaphore using buffered channel.
package main
import (
"fmt"
"log"
"math/rand/v2"
"sync"
"sync/atomic"
"time"
)
// Semaphore is a channel based semaphore.
type Semaphore chan struct{}
// New returns semaphore of size `size`.
func New(size int) (Semaphore, error) {
if size <= 0 {
return nil, fmt.Errorf("size (%d) <= 0", size)
}
s := make(Semaphore, size)
return s, nil
}
// Enter enters the semaphore.
func (s Semaphore) Enter() {
s <- struct{}{}
}
// Leave leaves the semaphore.
func (s Semaphore) Leave() {
<-s
}
func main() {
s, err := New(3)
if err != nil {
log.Fatal(err)
}
count := int64(0)
var wg sync.WaitGroup
for i := range 7 {
wg.Add(1)
go func() {
defer wg.Done()
for range 100 {
s.Enter()
v := atomic.AddInt64(&count, 1)
fmt.Printf("[%d] count=%d\n", i, v)
n := time.Duration(rand.IntN(100))
time.Sleep(n)
atomic.AddInt64(&count, -1)
s.Leave()
}
}()
}
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment