Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

synchronization/read-write-lock: peer connection router example implementation #115

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,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
Expand Down
110 changes: 110 additions & 0 deletions synchronization/read_write_lock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# 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 from incoming connections

```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
// ...some code here

// reading operation 1
connection := router.Query("192.168.1.1:8080")

//... more code here
// reading operation 2
otherQuery:= router.Query("192.168.1.1:8081")
// read locks are like counters.. until counter = 0 Write can be acquired

```