From 487d8420049c091538bfc622544cd12cafa3f1f8 Mon Sep 17 00:00:00 2001 From: geolffreym Date: Sat, 11 Jun 2022 09:46:41 -0600 Subject: [PATCH 1/3] synchronization/read-write-lock: peer connection router example implementation --- synchronization/read_write_lock.md | 111 +++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 synchronization/read_write_lock.md diff --git a/synchronization/read_write_lock.md b/synchronization/read_write_lock.md new file mode 100644 index 0000000..644d383 --- /dev/null +++ b/synchronization/read_write_lock.md @@ -0,0 +1,111 @@ +# Read/Write Lock Pattern +Allows parallel read access, but only exclusive access on write operations to a resource + +## Implementation + +```go +package router + +import ( + "sync" +) + +type Socket string +type Peer interface { + socket Socket + connection net.Conn +} + +func (p *Peer) Socket() Socket { + return p.socket +} + +// Router hash table to associate Socket with Peers. +// Unstructured mesh architecture +// eg. {127.0.0.1:4000: Peer} +type Router struct { + sync.RWMutex + table map[Socket]Peer +} + + +// Return connection interface based on socket +func (r *Router) Query(socket Socket) *Peer { + // Mutex for reading topics. + // Do not write while topics are read. + // Write Lock can’t be acquired until all Read Locks are released. + r.RWMutex.RLock() + defer r.RWMutex.RUnlock() + + if peer, ok := r.table[socket]; ok { + return peer + } + + return nil +} + +// Add create new socket connection association +func (r *Router) Add(peer *Peer) { + // Lock write table while add operation + // A blocked Lock call excludes new readers from acquiring the lock. + r.RWMutex.Lock() + r.table[peer.Socket()] = peer + r.RWMutex.Unlock() +} + +// Delete removes a connection from router +func (r *Router) Delete(peer *Peer) { + // Lock write table while delete operation + // A blocked Lock call excludes new readers from acquiring the lock. + r.RWMutex.Lock() + delete(r.table, peer.Socket()) + r.RWMutex.Unlock() +} +``` + +## Usage +### Syncronize routing peers + +```go + +// New router +router:= &Router{ + table: make(map[Socket]Peer) +} + +// !Important: +// 1 - Write Lock can’t be acquired until all Read Locks are released. +// 2 - A blocked Lock call excludes new readers from acquiring the lock. + +// Writing operation +go func(r *Router){ + for { + // this will be running waiting for new connections + /// .. some code here + conn, err := listener.Accept() + // eg. 192.168.1.1:8080 + remote := connection.RemoteAddr().String() + socket := Socket(address) + // New peer + peer := &Peer{ + socket: socket, + connection: conn + } + // Here we need a write lock to avoid race condition + r.Add(peer) + } +}(router) + +// Reading operation +go func(r *Router){ + // ...some logic here + // reading operation 1 + connection := r.Query("192.168.1.1:8080") + //... more code here + // reading operation 2 + otherQuery:= r.Query("192.168.1.1:8081") + // read locks are like counters.. + // until counter = 0 Write can be acquired +}(router) + +``` \ No newline at end of file From a99ebbcebf3a4e3a883dc0feaca2830d1cb3af87 Mon Sep 17 00:00:00 2001 From: geolffreym Date: Sat, 11 Jun 2022 09:47:54 -0600 Subject: [PATCH 2/3] docs: add check to README file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5450584..034f762 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ A curated collection of idiomatic design & application patterns for Go language. | [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 | ✘ | | [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 | ✔ | ## Concurrency Patterns From 14a9fa097ba719047fb31132522d7d9bd2419453 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Sat, 11 Jun 2022 09:48:52 -0600 Subject: [PATCH 3/3] Update read_write_lock.md --- synchronization/read_write_lock.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/synchronization/read_write_lock.md b/synchronization/read_write_lock.md index 644d383..5ca9eca 100644 --- a/synchronization/read_write_lock.md +++ b/synchronization/read_write_lock.md @@ -8,6 +8,7 @@ package router import ( "sync" + "net" ) type Socket string @@ -108,4 +109,4 @@ go func(r *Router){ // until counter = 0 Write can be acquired }(router) -``` \ No newline at end of file +```