Added fifo mutex

This commit is contained in:
Quentin Renard
2024-11-24 15:06:11 +01:00
parent 20f199d29c
commit bf9b3282fb
2 changed files with 74 additions and 0 deletions

48
sync.go
View File

@@ -554,3 +554,51 @@ func (d *AtomicDuration) Duration() time.Duration {
defer d.m.Unlock()
return d.d
}
// FIFOMutex is a mutex guaranteeing FIFO order
type FIFOMutex struct {
busy bool
m sync.Mutex // Locks busy and waiting
waiting []*sync.Cond
}
func (m *FIFOMutex) Lock() {
// No need to wait
m.m.Lock()
if !m.busy {
m.busy = true
m.m.Unlock()
return
}
// Create cond
c := sync.NewCond(&sync.Mutex{})
// Make sure to lock cond when waiting mutex is still held
c.L.Lock()
// Add to waiting queue
m.waiting = append(m.waiting, c)
m.m.Unlock()
// Wait
c.Wait()
}
func (m *FIFOMutex) Unlock() {
// Lock
m.m.Lock()
defer m.m.Unlock()
// Waiting queue is empty
if len(m.waiting) == 0 {
m.busy = false
return
}
// Signal and remove first item in waiting queue
m.waiting[0].L.Lock()
m.waiting[0].Signal()
m.waiting[0].L.Unlock()
m.waiting = m.waiting[1:]
}

View File

@@ -192,3 +192,29 @@ func TestDebugMutex(t *testing.T) {
t.Fatalf("%s doesn't contain %s", g, s)
}
}
func TestFIFOMutex(t *testing.T) {
m := FIFOMutex{}
var r []int
m.Lock()
wg := sync.WaitGroup{}
testFIFOMutex(1, &m, &r, &wg)
m.Unlock()
wg.Wait()
if e, g := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, r; !reflect.DeepEqual(e, g) {
t.Fatalf("expected %v, got %v", e, g)
}
}
func testFIFOMutex(i int, m *FIFOMutex, r *[]int, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
defer wg.Done()
if i < 10 {
testFIFOMutex(i+1, m, r, wg)
}
m.Lock()
*r = append(*r, i)
m.Unlock()
}()
}