lock

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 20, 2022 License: Apache-2.0 Imports: 7 Imported by: 1

README

go-lock

GoDev Build Status Go Report Card Codecov Coverage Status License Sourcegraph Mentioned in Awesome Go FOSSA Status

go-lock is a Golang library implementing an effcient read-write lock with the following built-in mechanism:

  • Mutex with timeout mechanism
  • Trylock
  • No-starve read-write solution

Native sync/Mutex and sync/RWMutex are very powerful and reliable. However, it became a disaster if the lock was not released as expected. Or, someone was holding the lock too long at the peak time leading whole system blocked. Dealing with those cases, go-lock implements TryLock, TryLockWithTimeout and TryLockWithContext function in addition to Lock and Unlock. It provides flexibility to control the resources.

Installation

go get github.com/viney-shih/go-lock

Example

package main

import (
	"fmt"
	"sync/atomic"
	"time"

	lock "github.com/viney-shih/go-lock"
)

func main() {
	// set RWMutex with CAS mechanism (CASMutex).
	var rwMut lock.RWMutex = lock.NewCASMutex()
	// set default value
	count := int32(0)

	// block here
	rwMut.Lock()
	go func() {
		time.Sleep(50 * time.Millisecond)
		fmt.Println("Now is", atomic.AddInt32(&count, 1)) // Now is 1
		rwMut.Unlock()
	}()

	// waiting for previous goroutine releasing the lock, and locking it again
	rwMut.Lock()
	fmt.Println("Now is", atomic.AddInt32(&count, 2)) // Now is 3

	// TryLock without blocking
	// Return false, because the lock is not released.
	fmt.Println("Return", rwMut.TryLock())

	// RTryLockWithTimeout without blocking
	// Return false, because the lock is not released.
	fmt.Println("Return", rwMut.RTryLockWithTimeout(50*time.Millisecond))

	// TryLockWithContext without blocking
	ctx, cancel := context.WithTimeout(context.TODO(), 50*time.Millisecond)
	defer cancel()
	// Return false, because the lock is not released.
	fmt.Println("Return", rwMut.TryLockWithContext(ctx))

	// release the lock in the end.
	rwMut.Unlock()

	// Output:
	// Now is 1
	// Now is 3
	// Return false
	// Return false
	// Return false
}

Benchmarks

  • Run on MacBook Pro (Retina, 15-inch, Mid 2015) 2.5 GHz Quad-Core Intel Core i7 16 GB 1600 MHz DDR3 using Go 1.15.2
  • Run with 1, 2, 4, 8 and 16 cpu to show it scales well...16 is double the # of logical cores on this machine.
go test -cpu=1,2,4,8,16 -bench=. -benchmem=true

goos: darwin
goarch: amd64
pkg: github.com/viney-shih/go-lock

(sync.RWMutex)
BenchmarkRWMutexLock                       	42591765	        27.4 ns/op	       0 B/op	       0 allocs/op
BenchmarkRWMutexLock-2                     	42713179	        27.5 ns/op	       0 B/op	       0 allocs/op
BenchmarkRWMutexLock-4                     	44348323	        27.5 ns/op	       0 B/op	       0 allocs/op
BenchmarkRWMutexLock-8                     	44135148	        27.9 ns/op	       0 B/op	       0 allocs/op
BenchmarkRWMutexLock-16                    	43566165	        27.5 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentRWMutexLock             	42971319	        27.5 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentRWMutexLock-2           	20131005	        57.5 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentRWMutexLock-4           	10752337	       115 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentRWMutexLock-8           	11434335	       105 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentRWMutexLock-16          	10495626	       109 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrent50RWMutexLock           	27979630	        42.8 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrent50RWMutexLock-2         	13037742	        86.6 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrent50RWMutexLock-4         	 9143397	       134 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrent50RWMutexLock-8         	 8335652	       139 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrent50RWMutexLock-16        	 7876855	       150 ns/op	       0 B/op	       0 allocs/op

(ChanMutex)
BenchmarkChanMutexLock                     	22619928	        51.8 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexLock-2                   	22769630	        51.6 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexLock-4                   	23096103	        51.7 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexLock-8                   	22627267	        51.1 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexLock-16                  	23092266	        51.7 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexLock           	23422556	        51.8 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexLock-2         	 6101949	       201 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexLock-4         	 5882083	       200 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexLock-8         	 5827183	       211 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexLock-16        	 5577098	       215 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexTryLock                  	22272500	        51.8 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexTryLock-2                	23004806	        52.2 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexTryLock-4                	22461870	        52.3 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexTryLock-8                	22901328	        53.8 ns/op	       0 B/op	       0 allocs/op
BenchmarkChanMutexTryLock-16               	22334739	        55.4 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexTryLock        	22112250	        53.9 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexTryLock-2      	13806072	        85.0 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexTryLock-4      	45892635	        32.6 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexTryLock-8      	396310569	         2.86 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentChanMutexTryLock-16     	512990590	         2.35 ns/op	       0 B/op	       0 allocs/op

(CASMutex)
BenchmarkCASMutexLock                      	 6160122	       186 ns/op	      96 B/op	       1 allocs/op
BenchmarkCASMutexLock-2                    	 7507022	       156 ns/op	      96 B/op	       1 allocs/op
BenchmarkCASMutexLock-4                    	 7646648	       156 ns/op	      96 B/op	       1 allocs/op
BenchmarkCASMutexLock-8                    	 7559616	       156 ns/op	      96 B/op	       1 allocs/op
BenchmarkCASMutexLock-16                   	 7576237	       158 ns/op	      96 B/op	       1 allocs/op
BenchmarkConcurrentCASMutexLock            	 6375879	       185 ns/op	      96 B/op	       1 allocs/op
BenchmarkConcurrentCASMutexLock-2          	 1690890	       706 ns/op	     251 B/op	       3 allocs/op
BenchmarkConcurrentCASMutexLock-4          	 1677104	       714 ns/op	     255 B/op	       3 allocs/op
BenchmarkConcurrentCASMutexLock-8          	 1808582	       639 ns/op	     255 B/op	       3 allocs/op
BenchmarkConcurrentCASMutexLock-16         	 1918422	       622 ns/op	     255 B/op	       3 allocs/op
BenchmarkConcurrent50CASMutexLock          	 5650274	       210 ns/op	      96 B/op	       1 allocs/op
BenchmarkConcurrent50CASMutexLock-2        	 1698381	       707 ns/op	     247 B/op	       3 allocs/op
BenchmarkConcurrent50CASMutexLock-4        	 1697070	       707 ns/op	     255 B/op	       3 allocs/op
BenchmarkConcurrent50CASMutexLock-8        	 1809859	       655 ns/op	     255 B/op	       3 allocs/op
BenchmarkConcurrent50CASMutexLock-16       	 1801652	       646 ns/op	     256 B/op	       4 allocs/op
BenchmarkCASMutexTryLock                   	 6593228	       182 ns/op	      96 B/op	       1 allocs/op
BenchmarkCASMutexTryLock-2                 	 7703084	       154 ns/op	      96 B/op	       1 allocs/op
BenchmarkCASMutexTryLock-4                 	 7790750	       151 ns/op	      96 B/op	       1 allocs/op
BenchmarkCASMutexTryLock-8                 	 7756263	       152 ns/op	      96 B/op	       1 allocs/op
BenchmarkCASMutexTryLock-16                	 7741186	       152 ns/op	      96 B/op	       1 allocs/op
BenchmarkConcurrentCASMutexTryLock         	 6509828	       189 ns/op	      96 B/op	       1 allocs/op
BenchmarkConcurrentCASMutexTryLock-2       	14058355	        82.2 ns/op	      17 B/op	       0 allocs/op
BenchmarkConcurrentCASMutexTryLock-4       	16875369	        71.4 ns/op	       8 B/op	       0 allocs/op
BenchmarkConcurrentCASMutexTryLock-8       	10985379	       109 ns/op	       4 B/op	       0 allocs/op
BenchmarkConcurrentCASMutexTryLock-16      	12405752	       104 ns/op	       1 B/op	       0 allocs/op
BenchmarkConcurrent50CASMutexTryLock       	 5631146	       204 ns/op	      96 B/op	       1 allocs/op
BenchmarkConcurrent50CASMutexTryLock-2     	 6518946	       182 ns/op	      61 B/op	       0 allocs/op
BenchmarkConcurrent50CASMutexTryLock-4     	 6937346	       174 ns/op	      43 B/op	       0 allocs/op
BenchmarkConcurrent50CASMutexTryLock-8     	 6493034	       182 ns/op	      39 B/op	       0 allocs/op
BenchmarkConcurrent50CASMutexTryLock-16    	 6177854	       202 ns/op	      41 B/op	       0 allocs/op
PASS

References

License

Apache-2.0

FOSSA Status

Documentation

Overview

Package go-lock is a Golang library implementing an effcient read-write lock with the following built-in mechanism:

1) Mutex with timeout mechanism

2) Trylock

3) No-starve read-write solution

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CASMutex

type CASMutex struct {
	// contains filtered or unexported fields
}

CASMutex is the struct implementing RWMutex with CAS mechanism.

Example
// set RWMutex with CAS mechanism (CASMutex).
var rwMut lock.RWMutex = lock.NewCASMutex()
// set default value
count := int32(0)

// block here
rwMut.Lock()
go func() {
	time.Sleep(50 * time.Millisecond)
	fmt.Println("Now is", atomic.AddInt32(&count, 1)) // Now is 1
	rwMut.Unlock()
}()

// waiting for previous goroutine releasing the lock, and locking it again
rwMut.Lock()
fmt.Println("Now is", atomic.AddInt32(&count, 2)) // Now is 3

// TryLock without blocking
// Return false, because the lock is not released.
fmt.Println("Return", rwMut.TryLock())

// RTryLockWithTimeout without blocking
// Return false, because the lock is not released.
fmt.Println("Return", rwMut.RTryLockWithTimeout(50*time.Millisecond))

// TryLockWithContext without blocking
ctx, cancel := context.WithTimeout(context.TODO(), 50*time.Millisecond)
defer cancel()
// Return false, because the lock is not released.
fmt.Println("Return", rwMut.TryLockWithContext(ctx))

// release the lock in the end.
rwMut.Unlock()
Output:

Now is 1
Now is 3
Return false
Return false
Return false

func NewCASMutex

func NewCASMutex() *CASMutex

NewCASMutex returns CASMutex

func (*CASMutex) Lock

func (m *CASMutex) Lock()

Lock acquires the lock. If it is currently held by others, Lock will wait until it has a chance to acquire it.

func (*CASMutex) RLock

func (m *CASMutex) RLock()

RLock acquires the read lock. If it is currently held by others writing, RLock will wait until it has a chance to acquire it.

func (*CASMutex) RLocker

func (m *CASMutex) RLocker() sync.Locker

RLocker returns a Locker interface that implements the Lock and Unlock methods by calling CASMutex.RLock and CASMutex.RUnlock.

func (*CASMutex) RTryLock

func (m *CASMutex) RTryLock() bool

RTryLock attempts to acquire the read lock without blocking. Return false if someone is writing it now.

func (*CASMutex) RTryLockWithContext

func (m *CASMutex) RTryLockWithContext(ctx context.Context) bool

RTryLockWithContext attempts to acquire the read lock, blocking until resources are available or ctx is done (timeout or cancellation).

func (*CASMutex) RTryLockWithTimeout

func (m *CASMutex) RTryLockWithTimeout(duration time.Duration) bool

RTryLockWithTimeout attempts to acquire the read lock within a period of time. Return false if spending time is more than duration and no chance to acquire it.

func (*CASMutex) RUnlock

func (m *CASMutex) RUnlock()

RUnlock releases the read lock.

func (*CASMutex) TryLock

func (m *CASMutex) TryLock() bool

TryLock attempts to acquire the lock without blocking. Return false if someone is holding it now.

func (*CASMutex) TryLockWithContext

func (m *CASMutex) TryLockWithContext(ctx context.Context) bool

TryLockWithContext attempts to acquire the lock, blocking until resources are available or ctx is done (timeout or cancellation).

func (*CASMutex) TryLockWithTimeout

func (m *CASMutex) TryLockWithTimeout(duration time.Duration) bool

TryLockWithTimeout attempts to acquire the lock within a period of time. Return false if spending time is more than duration and no chance to acquire it.

func (*CASMutex) Unlock

func (m *CASMutex) Unlock()

Unlock releases the lock.

type ChanMutex

type ChanMutex struct {
	// contains filtered or unexported fields
}

ChanMutex is the struct implementing Mutex by channel.

func NewChanMutex

func NewChanMutex() *ChanMutex

NewChanMutex returns ChanMutex.

func (*ChanMutex) Lock

func (m *ChanMutex) Lock()

Lock acquires the lock. If it is currently held by others, Lock will wait until it has a chance to acquire it.

func (*ChanMutex) TryLock

func (m *ChanMutex) TryLock() bool

TryLock attempts to acquire the lock without blocking. Return false if someone is holding it now.

func (*ChanMutex) TryLockWithContext

func (m *ChanMutex) TryLockWithContext(ctx context.Context) bool

TryLockWithContext attempts to acquire the lock, blocking until resources are available or ctx is done (timeout or cancellation).

func (*ChanMutex) TryLockWithTimeout

func (m *ChanMutex) TryLockWithTimeout(duration time.Duration) bool

TryLockWithTimeout attempts to acquire the lock within a period of time. Return false if spending time is more than duration and no chance to acquire it.

func (*ChanMutex) Unlock

func (m *ChanMutex) Unlock()

Unlock releases the lock.

type Group

type Group interface {
	Lock(key interface{})
	TryLock(key interface{}) bool
	TryLockWithTimeout(key interface{}, duration time.Duration) bool
	TryLockWithContext(key interface{}, ctx context.Context) bool
	Unlock(key interface{})
	UnlockAndFree(key interface{})
}

Group ...

func NewGroup

func NewGroup(fn func() Mutex) Group

type Mutex

type Mutex interface {
	// Lock acquires the lock.
	// If it is currently held by others, Lock will wait until it has a chance to acquire it.
	Lock()
	// TryLock attempts to acquire the lock without blocking.
	// Return false if someone is holding it now.
	TryLock() bool
	// TryLockWithTimeout attempts to acquire the lock within a period of time.
	// Return false if spending time is more than duration and no chance to acquire it.
	TryLockWithTimeout(time.Duration) bool
	// TryLockWithContext attempts to acquire the lock, blocking until resources
	// are available or ctx is done (timeout or cancellation).
	TryLockWithContext(ctx context.Context) bool
	// Unlock releases the lock.
	Unlock()
}

Mutex is a mutual exclusion lock, and must not be copied after first use.

func NewCASMutexInterface added in v1.3.0

func NewCASMutexInterface() Mutex

func NewChanMutexInterface added in v1.3.0

func NewChanMutexInterface() Mutex

type RWMutex

type RWMutex interface {
	Mutex

	// RLock acquires the read lock.
	// If it is currently held by others writing, RLock will wait until it has a chance to acquire it.
	RLock()
	// RTryLock attempts to acquire the read lock without blocking.
	// Return false if someone is writing it now.
	RTryLock() bool
	// RTryLockWithTimeout attempts to acquire the read lock within a period of time.
	// Return false if spending time is more than duration and no chance to acquire it.
	RTryLockWithTimeout(time.Duration) bool
	// RTryLockWithContext attempts to acquire the read lock, blocking until resources
	// are available or ctx is done (timeout or cancellation).
	RTryLockWithContext(ctx context.Context) bool
	// RUnlock releases the read lock.
	RUnlock()
	// RLocker returns a Locker interface that implements the Lock and Unlock methods
	// by calling rw.RLock and rw.RUnlock.
	RLocker() sync.Locker
}

RWMutex is a reader/writer mutual exclusion lock. The lock can be held by an arbitrary number of readers or a single writer. It must not be copied after first use.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL