mirror of
https://github.com/crazybber/awesome-patterns.git
synced 2024-11-22 04:36:02 +03:00
Merge pull request #9 from geolffreym/master
synchronization/read-write-lock: peer connection router example imple…
This commit is contained in:
commit
900e63c001
@ -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 | ✘ |
|
| [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 | ✔ |
|
||||||
|
|
||||||
## Concurrency Patterns
|
## Concurrency Patterns
|
||||||
|
112
synchronization/read_write_lock.md
Normal file
112
synchronization/read_write_lock.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# Read/Write Lock Pattern
|
||||||
|
Allows parallel read access, but only exclusive access on write operations to a resource
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
```go
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user