Skip to content

Instantly share code, notes, and snippets.

@ChristopherDavenport
Last active March 31, 2024 14:26
Show Gist options
  • Save ChristopherDavenport/2ee9e7dcf23ea02e1d2c0eb6f7d64e9a to your computer and use it in GitHub Desktop.
Save ChristopherDavenport/2ee9e7dcf23ea02e1d2c0eb6f7d64e9a to your computer and use it in GitHub Desktop.
SingleRoutine Failed Idea
package main
package main
import (
"log"
"math/rand"
"strconv"
"sync"
"sync/atomic"
"time"
)
func main() {
block := make(chan string)
f := func() (string, error) {
<-block
time.Sleep(1 * time.Second)
return strconv.Itoa(rand.Intn(1000)), nil
}
fancy := Prepare[string](f)
wg := sync.WaitGroup{}
wg.Add(2)
myTest := func() {
s, err := fancy()
if err != nil {
log.Default().Fatal(err)
} else {
log.Default().Println(s)
}
wg.Done()
}
go myTest()
go myTest()
close(block)
wg.Wait()
}
package single_routine
import (
"log"
"sync"
"sync/atomic"
)
type deferred[B any] struct {
b B
err error
wg sync.WaitGroup
}
func Prepare[B any](f func() (B, error)) func() (B, error) {
var myFunction func() (B, error)
ref := atomic.Pointer[deferred[B]]{}
myFunction = func() (B, error) {
result := &deferred[B]{}
result.wg.Add(1) // prime the wg
if ref.CompareAndSwap(nil, result) { // race for leadership, exactly one wins
result.b, result.err = f() // no need for atomics here, all writes happen before all reads
result.wg.Done() // broadcast
ref.CompareAndSwap(result, nil) // Reset, assuming nothing went wrong
return result.b, result.err
} else { // lost the race, we're a follower now
now := ref.Load() // load the result
if now == nil { // If we not were reset between the swap and the load recurse
return myFunction()
} else {
now.wg.Wait() // wait for signal
return now.b, now.err // these reads happen after the writes per wg semantics
}
}
}
return myFunction
}
// func PrepareFunction[A comparable, B any](f func (A) (B, error)) func (A) (B, error) {
// var myFunction func (A) (B, error)
// type Deferred struct {
// b B
// err error
// cond sync.Cond
// }
// // ref := atomic.Pointer[Deferred]{}
// m := sync.Map{}
// myFunction = func(a A) (B, error) {
// def := Deferred{}
// init, _ := m.Load(a)
// if init == nil && m.CompareAndSwap(a, init, &def) {
// out, err := f(a)
// def.b = out
// def.err = err
// def.cond.Broadcast()
// m.CompareAndDelete(a, &def)
// return def.b, def.err
// } else {
// // var deferred Deferred
// // If Empty || If Failed to Set
// now, _ := m.Load(a)
// if (now == nil) { // If became empty in the meantime, spin
// return myFunction(a)
// } else {
// def = now.(Deferred)
// return def.b, def.err
// }
// }
// }
// return myFunction
// }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment