DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
MediumMachine Coding

Implement a Counting Semaphore

234 views

Problem Statement

Implement a counting semaphore with Acquire(n) and Release(n) operations that blocks if not enough permits are available.

Requirements

  • Acquire(n): Block until n permits are available, then consume them
  • Release(n): Return n permits to the pool
  • TryAcquire(n): Non-blocking acquire, returns false if not enough permits
  • Thread-safe for concurrent access

Implementation with Channel

package semaphore

type Semaphore struct {
    permits chan struct{}
}

func New(maxPermits int) *Semaphore {
    s := &Semaphore{
        permits: make(chan struct{}, maxPermits),
    }
    // Fill with permits
    for i := 0; i < maxPermits; i++ {
        s.permits <- struct{}{}
    }
    return s
}

func (s *Semaphore) Acquire() {
    <-s.permits
}

func (s *Semaphore) AcquireN(n int) {
    for i := 0; i < n; i++ {
        <-s.permits
    }
}

func (s *Semaphore) Release() {
    s.permits <- struct{}{}
}

func (s *Semaphore) ReleaseN(n int) {
    for i := 0; i < n; i++ {
        s.permits <- struct{}{}
    }
}

func (s *Semaphore) TryAcquire() bool {
    select {
    case <-s.permits:
        return true
    default:
        return false
    }
}

Implementation with sync.Cond

package semaphore

import "sync"

type CondSemaphore struct {
    permits int
    max     int
    cond    *sync.Cond
}

func NewCond(maxPermits int) *CondSemaphore {
    return &CondSemaphore{
        permits: maxPermits,
        max:     maxPermits,
        cond:    sync.NewCond(&sync.Mutex{}),
    }
}

func (s *CondSemaphore) Acquire(n int) {
    s.cond.L.Lock()
    defer s.cond.L.Unlock()
    
    for s.permits < n {
        s.cond.Wait()
    }
    s.permits -= n
}

func (s *CondSemaphore) Release(n int) {
    s.cond.L.Lock()
    defer s.cond.L.Unlock()
    
    s.permits += n
    if s.permits > s.max {
        s.permits = s.max
    }
    s.cond.Broadcast()
}

Usage: Limit Concurrent Database Connections

var dbSem = semaphore.New(10) // Max 10 concurrent queries

func QueryDB(query string) (Result, error) {
    dbSem.Acquire()
    defer dbSem.Release()
    
    return db.Query(query)
}

Production Library

import "golang.org/x/sync/semaphore"

sem := semaphore.NewWeighted(10)

ctx := context.Background()
if err := sem.Acquire(ctx, 3); err != nil {
    return err
}
defer sem.Release(3)

Sample Test Cases

Case 1
Input
permits=3, acquire=2
Expected Output
Successfully acquires 2 permits, 1 remaining
Case 2
Input
permits=2, acquire=3
Expected Output
Third acquire blocks until permit released
Case 3
Input
["Acquire(1)", "Release(1)"]
Expected Output
null
Case 4
Input
["Acquire(3)", "Release(2)", "Acquire(1)"]
Expected Output
null
Case 5
Input
["TryAcquire(5)", "Release(2)", "TryAcquire(3)"]
Expected Output
[true, null, true]

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
234
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go