Skip to content

Instantly share code, notes, and snippets.

@bwangelme
Created April 16, 2019 15:21
Show Gist options
  • Save bwangelme/44f0edb469733bf9bac86bbc96faf037 to your computer and use it in GitHub Desktop.
Save bwangelme/44f0edb469733bf9bac86bbc96faf037 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"log"
"sync"
)
const endNum = 30
type FairLock struct {
mu *sync.Mutex
cond *sync.Cond
isHold bool
holdCount int
}
func NewFairLock() sync.Locker {
mu := new(sync.Mutex)
cond := sync.NewCond(mu)
return &FairLock{
holdCount: 0,
isHold: false,
mu: mu,
cond: cond,
}
}
func (fl *FairLock) Lock() {
fl.mu.Lock()
defer fl.mu.Unlock()
if !fl.isHold {
fl.holdCount++
fl.isHold = true
return
}
fl.holdCount++
for fl.isHold {
fl.cond.Wait()
}
fl.isHold = true
}
func (fl *FairLock) Unlock() {
fl.mu.Lock()
defer fl.mu.Unlock()
if !fl.isHold {
log.Fatal("unlock of UnLocked mutex")
}
if fl.holdCount > 1 {
fl.cond.Signal()
}
fl.isHold = false
fl.holdCount--
}
var (
end = make(chan struct{})
i int
)
func threadPrint(threadNum int, threadName string, locker sync.Locker) {
for i < endNum {
locker.Lock()
if i >= endNum {
locker.Unlock()
continue
}
if i%3 != threadNum {
locker.Unlock()
continue
}
fmt.Printf("%d: %s\n", i, threadName)
i += 1
locker.Unlock()
}
end <- struct{}{}
}
func main() {
mu := NewFairLock()
names := []string{"A", "B", "C"}
for idx, name := range names {
go threadPrint(idx, name, mu)
}
for _ = range names {
<-end
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment