lock

package module
v1.1.2 Latest Latest
Warning

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

Go to latest
Published: Jun 18, 2022 License: Apache-2.0 Imports: 7 Imported by: 21

README

go-lock

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

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 added in v1.1.0

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 added in v1.0.1

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 added in v1.0.1

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 added in v1.0.1

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 Mutex added in v1.1.0

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.

type RWMutex added in v1.1.0

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