lock

package
v0.0.0-...-f32f910 Latest Latest
Warning

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

Go to latest
Published: Apr 2, 2022 License: MIT Imports: 4 Imported by: 0

README

Locks

This package is a diagnostic package to track where lock contention occurs. When used instead of a sync.RWMutex, you can register the calling method's name, then print a report that shows which locks are currently being held.

Basic usage:

type MyStruct struct {
    lock.RWLock
}

def (m *MyStruct) MyFunc() {
    m.Lock("myfunc")
    defer m.Unlock("myfunc")
}

This package adds a bit of overhead to the locking process, so it is really only used for diagnostics.

Future Work

Future versions of this package will use runtime.Caller to identify which function is calling lock, making lock.Lock hot swappable with sync.Mutex!

Documentation

Overview

Package lock provides lock contention diagnostics for go mutexes.

This package provides a write-only mutex as well as a read and write mutex that can be swapped for the mutexes in the sync package. They extend the sync package by tracking the caller when they request a lock or unlock.

If lock contention is experienced in such a way that the program doesn't panic (primarily when there are many go routines all making progress in different parts of the program), you can print a report of which callers are attempting to acquire locks, and which callers have not released their locks yet, helping to diagnose contention issues.

Index

Examples

Constants

View Source
const UnknownCaller = "unknown caller"

UnknownCaller is used as the default caller if we cannot query it.

Variables

This section is empty.

Functions

This section is empty.

Types

type MutexD

type MutexD struct {
	sync.Mutex
	// contains filtered or unexported fields
}

MutexD wraps sync.Mutex to provide tracking for methods that call the lock object. Use the same way you would use a Mutex!

Example
l := new(Lockable)
go l.Alpha()
time.Sleep(10 * time.Millisecond)
for i := 0; i < 2; i++ {
	go l.Bravo()
}
fmt.Println(l.MutexD.String())
Output:

1 locks requested by github.com/bbengfort/x/lock.(*Lockable).Alpha
2 locks requested by github.com/bbengfort/x/lock.(*Lockable).Bravo

func (*MutexD) Init

func (l *MutexD) Init()

Init the lock and internal data structures like the map. No need to Init() manually though as the lock methods do a check to ensure that it's ready.

func (*MutexD) Lock

func (l *MutexD) Lock()

Lock the data structure, blocking all other calls that are requesting a lock until unlock is called. This method provides diagnostic information by recording the caller of the lock in an internal map. You can print a report to see who is attempting to acquire a lock and who is still holding any locks in the system.

func (*MutexD) String

func (l *MutexD) String() string

String returns a report about who is attempting to acquire locks and which callers currently hold locks. E.g. if more than one lock is in the lock map than the first one is holding the lock and the others are awaiting it.

func (*MutexD) Unlock

func (l *MutexD) Unlock()

Unlock the data structure, allowing any other blocked calls that have requested a lock to acquire it. This method removes the caller from the internal map so it's easy to see who still is attempting to acquire locks and who has released them (or hasn't released them yet).

type RWMutexD

type RWMutexD struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

RWMutexD wraps a sync.RWMutex to provide tracking for methods that call the lock object. Use the same way you would use a mutex in order to diagnose requested read locks, write locks, and currently held read and write locks.

Example
l := new(RWLockable)
go l.Alpha()
time.Sleep(100 * time.Millisecond)
for i := 0; i < 2; i++ {
	go l.Bravo()
}
fmt.Println(l.RWMutexD.String())
Output:

1 locks requested by github.com/bbengfort/x/lock.(*Lockable).Alpha
2 read locks requested by github.com/bbengfort/x/lock.(*Lockable).Bravo

func (*RWMutexD) Init

func (l *RWMutexD) Init()

Init the lock and internal data structures like the maps. No need to call Init() manually, though, as the lock methods do a check beforehand.

func (*RWMutexD) Lock

func (l *RWMutexD) Lock()

Lock the data structure, blocking all other calls that are requesting a lock until unlock is called. This method provides diagnostic information by recording the caller of the lock in an internal map. You can print a report to see who is attempting to acquire a lock and who is still holding any locks in the system.

func (*RWMutexD) RLock

func (l *RWMutexD) RLock()

RLock the data structure, blocking all other calls that are requesting a lock until unlock is called. This method provides diagnostic information by recording the caller of the lock in an internal map. You can print a report to see who is attempting to acquire a lock and who is still holding any locks in the system.

func (*RWMutexD) RUnlock

func (l *RWMutexD) RUnlock()

RUnlock the data structure, allowing any other blocked calls that have requested a lock to acquire it. This method removes the caller from the internal map so it's easy to see who still is attempting to acquire locks and who has released them (or hasn't released them yet).

func (*RWMutexD) String

func (l *RWMutexD) String() string

String returns a report about who is attempting to acquire locks and which callers currently hold locks. E.g. if more than one lock is in the lock map than the first one is holding the lock and the others are awaiting it.

func (*RWMutexD) Unlock

func (l *RWMutexD) Unlock()

Unlock the data structure, allowing any other blocked calls that have requested a lock to acquire it. This method removes the caller from the internal map so it's easy to see who still is attempting to acquire locks and who has released them (or hasn't released them yet).

Jump to

Keyboard shortcuts

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