0
\$\begingroup\$

I'm extending the sync.Pool type by limiting the amount of objects that can reside outside the pool. To achieve this I'm using sync.Cond to wait until a call to Pool.Put is made. To prevent users from creating a zero value of my struct, I'm not exporting it and defined an interface too.

My question is: when checking the condition to Cond.Wait the sync package advises to Wait in a loop. But considering my current implementation I think that using an if suffices. Given the code below and assuming that nothing wil be modified, can I change the for loop around Cond.Wait to a simple if?

type pool struct {
    pool sync.Pool
    n    int
    max  int
    lock sync.Mutex
    cond *sync.Cond
}

type Pool interface {
    Get() any
    Put(x any)
}

func NewPool(n int, f func() any) Pool {
    p := &pool{
        pool: sync.Pool{
            New: f,
        },
        max: n,
    }
    p.cond = sync.NewCond(&p.lock)
    return p
}

func (p *pool) Get() any {
    p.lock.Lock()
    defer p.lock.Unlock()
    // change to if?
    for p.n >= p.max {
        p.cond.Wait()
    }
    p.n++
    return p.pool.Get()
}

func (p *pool) Put(x any) {
    p.pool.Put(x)
    p.lock.Lock()
    defer p.lock.Unlock()
    if p.n > 0 {
        p.n--
    }
    if p.n < p.max {
        p.cond.Signal()
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ Wait just releastes the mutex lock, and suspends the routine where Wait is called. When Wait returns, there's absolutely no way you can be certain that p.n >= p.max unless you check it again. You may think that Wait will return because Put was called, but Wait can return because another routine called Get. \$\endgroup\$ Aug 18 at 10:12
  • \$\begingroup\$ @EliasVanOotegem Why would Wait return when Get is called? \$\endgroup\$
    – Bernardo1r
    Aug 19 at 21:38
  • 1
    \$\begingroup\$ My bad, you're using Signal, using a conditional, though, would quickly become problematic if you switch over to Signal. this example is all in all rather simplistic, and real-world code more often than not does merit your Wait condition to be re-evaluated. The recommended pattern (and more defensive approach) therefore is to use a loop to ensure the condition is checked once Wait re-acquires the lock. You could technically use an if at the moment, but with the same number of lines, your code is, in many ways, better with the for \$\endgroup\$ Aug 24 at 16:42

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.