Acquiring Lock with Deadline in Go
In Go, the sync.Mutex type only provides Lock() and Unlock() methods. For scenarios where a lock acquisition should be attempted within a deadline, or potentially aborted immediately, there is no built-in solution.
Proposed Solution: Channel as Mutex
An alternative approach is to use a channel with a buffer size of one to simulate a mutex. By sending and receiving a single empty struct value (struct{}{}), lock and unlock operations can be performed.
Lock:
<code class="go">l := make(chan struct{}, 1) l <- struct{}{}</code>
Unlock:
<code class="go"><-l</code>
Try Lock:
<code class="go">select { case l <- struct{}{}: // lock acquired <-l default: // lock not acquired }</code>
Try Lock with Timeout:
<code class="go">select { case l <- struct{}{}: // lock acquired <-l case <-time.After(time.Minute): // lock not acquired }</code>
In the provided examples, s.someObj is assumed to be a map from key to value.
Example 1: LockBefore() for Latency Sensitive Code
<code class="go">// DoTheThing locks before performing expensive computations. func (s *RPCService) DoTheThing(ctx context.Context, ...) ... { l := make(chan struct{}, 1) select { case l <- struct{}{}: defer <-l ... expensive computation based on internal state ... default: return s.cheapCachedResponse[req.Parameter] } }</code>
Example 2: TryLock() for Updating Stats
<code class="go">// updateObjStats attempts to lock and update stats. func (s *StatsObject) updateObjStats(key, value interface{}) { l := make(chan struct{}, 1) select { case l <- struct{}{}: defer <-l ... update stats ... ... fill in s.cheapCachedResponse ... default: // skip locked object } } // UpdateStats attempts to lock and update stats for all objects. func (s *StatsObject) UpdateStats() { s.someObj.Range(s.updateObjStats) }</code>
The above is the detailed content of How to Acquire a Lock with a Deadline in Go?. For more information, please follow other related articles on the PHP Chinese website!