diff --git a/README.md b/README.md index 7d9f5f7..ecb902d 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ A curated collection of idiomatic design & application patterns for Go language. | 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 | ✘ | -| [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 | ✘ | | [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 | ✔ | diff --git a/synchronization/mutex.go b/synchronization/mutex.go new file mode 100644 index 0000000..6b15a1f --- /dev/null +++ b/synchronization/mutex.go @@ -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) +} diff --git a/synchronization/mutex.md b/synchronization/mutex.md new file mode 100644 index 0000000..3c8eeb6 --- /dev/null +++ b/synchronization/mutex.md @@ -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) +} +``` \ No newline at end of file