1
0
mirror of https://github.com/tmrts/go-patterns.git synced 2024-11-25 22:46:05 +03:00

synchronization/mutex: implement synchronization mutex/lock pattern

This commit is contained in:
Serge Bishyr 2017-10-13 17:57:11 +03:00
parent f978e42036
commit 4fa57a0eb9
3 changed files with 118 additions and 1 deletions

View File

@ -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
View 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
View 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)
}
```