github.com/dmmcquay/sia@v1.3.1-0.20180712220038-9f8d535311b9/sync/trymutex.go (about) 1 package sync 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 // TryMutex provides a mutex that allows you to attempt to grab a mutex, and 9 // then fail if the mutex is either not grabbed immediately or is not grabbed 10 // by the specified duration. 11 type TryMutex struct { 12 once sync.Once 13 lock chan struct{} 14 } 15 16 // init will create the channel that manages the lock. 17 func (tm *TryMutex) init() { 18 tm.lock = make(chan struct{}, 1) 19 tm.lock <- struct{}{} 20 } 21 22 // Lock grabs a lock on the TryMutex, blocking until the lock is obtained. 23 func (tm *TryMutex) Lock() { 24 tm.once.Do(tm.init) 25 26 <-tm.lock 27 } 28 29 // TryLock grabs a lock on the TryMutex, returning an error if the mutex is 30 // already locked. 31 func (tm *TryMutex) TryLock() bool { 32 tm.once.Do(tm.init) 33 select { 34 case <-tm.lock: 35 return true 36 default: 37 return false 38 } 39 } 40 41 // TryLockTimed grabs a lock on the TryMutex, returning an error if the mutex 42 // is not grabbed after the provided duration. 43 func (tm *TryMutex) TryLockTimed(t time.Duration) bool { 44 tm.once.Do(tm.init) 45 46 timer := time.NewTimer(t) 47 select { 48 case <-tm.lock: 49 timer.Stop() 50 return true 51 case <-timer.C: 52 return false 53 } 54 } 55 56 // Unlock releases a lock on the TryMutex. 57 func (tm *TryMutex) Unlock() { 58 tm.once.Do(tm.init) 59 60 select { 61 case tm.lock <- struct{}{}: 62 // Success - do nothing. 63 default: 64 panic("unlock called when TryMutex is not locked") 65 } 66 }