mirror of
https://github.com/tmrts/go-patterns.git
synced 2024-11-22 13:06:09 +03:00
synchronization/mutex: implement synchronization mutex/lock pattern
This commit is contained in:
parent
f978e42036
commit
4fa57a0eb9
@ -52,7 +52,7 @@ A curated collection of idiomatic design & application patterns for Go language.
|
|||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Condition Variable](/synchronization/condition_variable.md) | Provides a mechanism for threads to temporarily give up access in order to wait for some condition | ✘ |
|
| [Condition Variable](/synchronization/condition_variable.md) | Provides a mechanism for threads to temporarily give up access in order to wait for some condition | ✘ |
|
||||||
| [Lock/Mutex](/synchronization/mutex.md) | Enforces mutual exclusion limit on a resource to gain exclusive access | ✘ |
|
| [Lock/Mutex](/synchronization/mutex.md) | Enforces mutual exclusion limit on a resource to gain exclusive access | ✔ |
|
||||||
| [Monitor](/synchronization/monitor.md) | Combination of mutex and condition variable patterns | ✘ |
|
| [Monitor](/synchronization/monitor.md) | Combination of mutex and condition variable patterns | ✘ |
|
||||||
| [Read-Write Lock](/synchronization/read_write_lock.md) | Allows parallel read access, but only exclusive access on write operations to a resource | ✘ |
|
| [Read-Write Lock](/synchronization/read_write_lock.md) | Allows parallel read access, but only exclusive access on write operations to a resource | ✘ |
|
||||||
| [Semaphore](/synchronization/semaphore.md) | Allows controlling access to a common resource | ✔ |
|
| [Semaphore](/synchronization/semaphore.md) | Allows controlling access to a common resource | ✔ |
|
||||||
|
53
synchronization/mutex.go
Normal file
53
synchronization/mutex.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//dictionary inherits the mutex lock
|
||||||
|
type dictionary struct {
|
||||||
|
sync.Mutex
|
||||||
|
rel map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
//add a new key value pare if the given key is not present in the map
|
||||||
|
//returns an error if the given key is already present
|
||||||
|
func (d *dictionary) putIfAbsent(key string, value string) error {
|
||||||
|
//Locks the object, add the key-value pare to the map, and then unlock the object
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
if _, isPresent := d.rel[key]; isPresent {
|
||||||
|
return fmt.Errorf("key [%s] is already present in the dictionary", key)
|
||||||
|
}
|
||||||
|
d.rel[key] = value
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDictionary() dictionary {
|
||||||
|
return dictionary{
|
||||||
|
rel: make(map[string]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
d := newDictionary()
|
||||||
|
keys := []string{"foo", "bar", "baz", "bar"}
|
||||||
|
values := []string{"value1", "value2", "value3", "value4"}
|
||||||
|
for i := 0; i < len(keys); i++ {
|
||||||
|
// Starts a new goroutine
|
||||||
|
// that that add to the dictionary as a key string representation of i % 7
|
||||||
|
// and string representation of i as a value
|
||||||
|
go func(index int) {
|
||||||
|
err := d.putIfAbsent(keys[index], values[index])
|
||||||
|
if err != nil {
|
||||||
|
//print the error
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
//print the result
|
||||||
|
fmt.Println(d.rel)
|
||||||
|
}
|
64
synchronization/mutex.md
Normal file
64
synchronization/mutex.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Mutex/Lock pattern
|
||||||
|
A mutex is a synchronization pattern that allows exclusive access to shared data by locking and unlocking.
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
```go
|
||||||
|
package mutex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
//dictionary inherits the mutex lock
|
||||||
|
type Dictionary struct {
|
||||||
|
sync.Mutex
|
||||||
|
rel map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() Dictionary {
|
||||||
|
return Dictionary{
|
||||||
|
rel: make(map[string]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add a new key value pare if the given key is not present in the map
|
||||||
|
//returns an error if the given key is already present
|
||||||
|
func (d *Dictionary) PutIfAbsent(key string, value string) error {
|
||||||
|
d.Lock() //lock the object
|
||||||
|
defer d.Unlock() //unlock the object when the work is done
|
||||||
|
//return the error if key is already present in the map
|
||||||
|
if _, isPresent := d.rel[key]; isPresent {
|
||||||
|
return fmt.Errorf("key [%s] is already present in the dictionary", key)
|
||||||
|
}
|
||||||
|
d.rel[key] = value
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
d := mutext.New()
|
||||||
|
keys := []string{"foo", "bar", "baz", "bar"}
|
||||||
|
values := []string{"value1", "value2", "value3", "value4"}
|
||||||
|
for i := 0; i < len(keys); i++ {
|
||||||
|
// Starts a new goroutine
|
||||||
|
// that that add to the dictionary as a key string representation of i % 7
|
||||||
|
// and string representation of i as a value
|
||||||
|
go func(index int) {
|
||||||
|
err := d.putIfAbsent(keys[index], values[index])
|
||||||
|
if err != nil {
|
||||||
|
//print the error
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
//print the result
|
||||||
|
fmt.Println(d.rel)
|
||||||
|
}
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user