ConcurrentProgrammingWithGo icon indicating copy to clipboard operation
ConcurrentProgrammingWithGo copied to clipboard

Chatper 6 - Excersie 2 - Doubt

Open nivekithan opened this issue 10 months ago • 1 comments

In previous chapters, we saw the TryLock() operation on mutexes. This is a nonblocking call that returns immediately without waiting. If the lock is not available, the function returns false; otherwise, it locks the mutex and returns true. Can you write a similar non-blocking function called TryWait() on our implementation of a waitgroup from listing 6.8? This function will return immediately with false if the waitgroup is not done; otherwise, it returns true.

From my understanding is that TryWait should not block if the waitgroup is not done but the solution for it is

func (wg *WaitGrp) TryWait() bool {
	wg.cond.L.Lock()
	result := wg.groupSize == 0
	wg.cond.L.Unlock()
	return result
}
> wg.cond.L.Lock()

Doesn't this line block the current goroutine until it got exclusive access to cond.L mutex ?

Event though cond.L mutex is internal and get's blocked only for short time by these methods Add, Done, Wait. I was hoping we can implement a solution similar to Excerise 4.3 . Where we implement TryReadLock for our mutex.

Sharing solution for reference

func (rw *ReadWriteMutex) TryReadLock() bool {
    if rw.readersLock.TryLock() {
        globalSuccess := true
        if rw.readersCounter == 0 {
            globalSuccess = rw.globalLock.TryLock()
        }
        if globalSuccess {
            rw.readersCounter++
        }
        rw.readersLock.Unlock()
        return globalSuccess
    } else {
        return false
    }
}

Anyways my doubt is that is there any way to implement TryWait without waiting for cond.L.Lock too ?

nivekithan avatar Apr 21 '24 17:04 nivekithan

Hi there, Thank you for your question and for buying the book. The TryWait() implementation that is in the solutions package will not block until the wait group is done, which is the purpose of the exercise. However we can implement this also without using blocking mutex Lock() calls by using the TryLock() instead. Here is an example of one such implementation (disclaimer I haven't had much time to fully test this):

type WaitGrp struct {
	groupSize int
	cond      *sync.Cond
	mutex 	  *sync.Mutex
}

func NewWaitGrp() *WaitGrp {
	m := &sync.Mutex{}
	return &WaitGrp{
		cond: sync.NewCond(m),
		mutex: m,
	}
}

func (wg *WaitGrp) TryWait() bool {
	result := false
	if wg.mutex.TryLock() {
		result = wg.groupSize == 0
		wg.cond.L.Unlock()
	}
	return result
}

cutajarj avatar May 02 '24 16:05 cutajarj