Skip to content

Instantly share code, notes, and snippets.

@wrouesnel
Created March 11, 2020 03:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wrouesnel/b7170555a5e4db7aa03037a87f996599 to your computer and use it in GitHub Desktop.
Save wrouesnel/b7170555a5e4db7aa03037a87f996599 to your computer and use it in GitHub Desktop.
Building a struct which mode switches
// test application for how to switch modes
package main
import (
"fmt"
"sync"
"time"
)
type ReadMode interface {
}
type WriteMode interface {
ReadMode
}
type ModeSwitchable struct {
cond *sync.Cond
readers int
writers int
}
func (ms *ModeSwitchable) WithReadonly(fn func (ds ReadMode)) {
ms.cond.L.Lock()
for ms.writers > 0 {
ms.cond.Wait()
}
ms.readers++
ms.cond.L.Unlock()
ms.cond.Broadcast()
fn(ReadMode(ms))
ms.readers--
ms.cond.Broadcast()
}
func (ms *ModeSwitchable) WithAny(fn func (ds ReadMode)) {
fn(ReadMode(ms))
}
func (ms *ModeSwitchable) WhenWriteable(fn func (ds WriteMode)) {
ms.cond.L.Lock()
for ms.readers > 0 {
ms.cond.Wait()
}
ms.writers++
ms.cond.L.Unlock()
ms.cond.Broadcast()
fn(WriteMode(ms))
ms.writers--
ms.cond.Broadcast()
}
func main() {
fmt.Println("Started")
ms := ModeSwitchable{}
ms.cond = sync.NewCond(new(sync.Mutex))
ms.readers = 0
ms.writers = 0
go ms.WhenWriteable(func(ds WriteMode) {
fmt.Println("Long running writable started...", time.Now())
time.Sleep(time.Second*10)
fmt.Println("Long running writable finished", time.Now())
})
wg := new(sync.WaitGroup)
wg.Add(1)
go ms.WithReadonly(func(ds ReadMode) {
fmt.Println("Readonly during writeable", time.Now())
wg.Done()
})
wg.Add(1)
go ms.WithReadonly(func(ds ReadMode) {
fmt.Println("Readonly during writeable", time.Now())
wg.Done()
})
wg.Add(1)
go ms.WithReadonly(func(ds ReadMode) {
fmt.Println("Readonly during writeable", time.Now())
wg.Done()
})
time.Sleep(time.Second)
go ms.WhenWriteable(func(ds WriteMode) {
fmt.Println("Quick writeable 1 started", time.Now())
time.Sleep(time.Second * 3)
fmt.Println("Quick writeable 1 finished", time.Now())
})
go ms.WhenWriteable(func(ds WriteMode) {
fmt.Println("Quick writeable 2 started", time.Now())
time.Sleep(time.Second * 3)
fmt.Println("Quick writeable 2 finished", time.Now())
})
wg.Wait()
// Test trying to write during readonly
go ms.WithReadonly(func(ds ReadMode) {
fmt.Println("Long running readonly started...", time.Now())
time.Sleep(time.Second*10)
fmt.Println("Long running readonly finished", time.Now())
})
time.Sleep(time.Second)
wg.Add(1)
go ms.WhenWriteable(func(ds WriteMode) {
fmt.Println("Quick writeable 3 started", time.Now())
time.Sleep(time.Second * 3)
fmt.Println("Quick writeable 3 finished", time.Now())
wg.Done()
})
wg.Add(1)
go ms.WhenWriteable(func(ds WriteMode) {
fmt.Println("Quick writeable 4 started", time.Now())
time.Sleep(time.Second * 3)
fmt.Println("Quick writeable 4 finished", time.Now())
wg.Done()
})
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment