github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/18channeluse/trylock_timeout/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  )
     8  
     9  type Mutex struct {
    10  	ch chan struct{}
    11  }
    12  
    13  func NewMutex() *Mutex {
    14  	mu := &Mutex{make(chan struct{}, 1)}
    15  	mu.ch <- struct{}{}
    16  	return mu
    17  }
    18  
    19  func (m *Mutex) Lock() {
    20  	<-m.ch
    21  }
    22  
    23  func (m *Mutex) Unlock() {
    24  	select {
    25  	case m.ch <- struct{}{}:
    26  	default:
    27  		panic("unlock of unlocked mutex")
    28  	}
    29  }
    30  func (m *Mutex) TryLock(timeout time.Duration) bool {
    31  	timer := time.NewTimer(timeout)
    32  	select {
    33  	case <-m.ch:
    34  		timer.Stop()
    35  		return true
    36  	case <-time.After(timeout):
    37  	}
    38  	return false
    39  }
    40  
    41  // context的方式
    42  func (m *Mutex) TryLock2(timeout time.Duration) bool {
    43  	ctx, cancel := context.WithTimeout(context.TODO(), timeout)
    44  	select {
    45  	case <-m.ch:
    46  		cancel()
    47  		return true
    48  	case <-ctx.Done():
    49  		fmt.Println("err -> ", ctx.Err())
    50  	}
    51  	return false
    52  }
    53  
    54  func (m *Mutex) IsLocked() bool {
    55  	return len(m.ch) == 0
    56  }
    57  func main() {
    58  	m := NewMutex()
    59  	ok := m.TryLock(time.Second)
    60  	fmt.Printf("locked v %v\n", ok)
    61  	ok = m.TryLock(time.Second)
    62  	fmt.Printf("locked %v\n", ok)
    63  }