Merge pull request #9 from geolffreym/master

synchronization/read-write-lock: peer connection router example imple…
This commit is contained in:
Edward 2022-07-26 14:30:19 +08:00 committed by GitHub
commit 900e63c001
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 113 additions and 1 deletions

View File

@ -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

View 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 cant 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 cant 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)
```