I am trying to figure out what is that is making my program hanging, most of my locks shouldn't be held for more than 200 ms. (actually much less!)
I want to create two new functions (Lock()
and Unlock()
) so that Lock will have a timer that will panic if Lock has been held for more than 200 ms.
This is my current attempt, but it doesn't work, any hint?
type ShardKV struct {
lockChan chan bool
}
func (kv *App) lock(reason string) {
kv.mu.Lock()
f := func () {
fmt.Println("PANIC: ms passed")
select {
case <- kv.lockChan:
//
default:
panic("PANIC: " + reason)
}
}
time.AfterFunc(time.Second * 10, f)
}
func (kv *App) unlock(reason string) {
kv.lockChan <- true
kv.mu.Unlock()
}
Your lock function waits for 10 seconds befor calling the f function which holds the select statement, a simpler way of achieving what you are trying to do might be this:
func (kv *App) lock(reason string) {
kv.mu.Lock()
select {
case <- kv.lockChan:
//
case <-time.After(time.Second * 10):
panic("PANIC: " + reason)
}
}
You need to use the return value of time.AfterFunc
. Here is a working example:
package main
import (
"fmt"
"sync"
"time"
)
type Foo struct {
m sync.Mutex
timer *time.Timer
}
func (f *Foo) lock() {
f.m.Lock()
f.timer = time.AfterFunc(3 * time.Second, func() {
panic("Too long!")
})
}
func (f *Foo) unlock() {
f.timer.Stop()
f.m.Unlock()
}
func main() {
foo := &Foo{
sync.Mutex{},
&time.Timer{},
}
foo.lock()
// Uncomment this to see the difference
//time.Sleep(5 * time.Second)
foo.unlock()
fmt.Println("Success!")
}
Playground link: https://play.golang.org/p/WVPp0_Iqlb
You have said you want your code to panic if the lock has been hold for 200 ms, but you gave the timer 10 seconds to wait. This will simply wait for 10 seconds before panicing instead of 200. I have tried your code editing it the following way :
package main
import (
"sync"
"fmt"
"time"
)
type App struct {
mu sync.Mutex
lockChan chan bool
}
func (kv *App) lock(reason string) {
kv.mu.Lock()
f := func () {
fmt.Println("PANIC: ms passed")
select {
case <- kv.lockChan:
//
default:
panic("PANIC: " + reason)
}
}
time.AfterFunc(time.Millisecond * 200, f)
}
func (kv *App) unlock(reason string) {
kv.lockChan <- true
kv.mu.Unlock()
}
func NewApp() *App {
app := App{}
app.lockChan = make(chan bool)
return &app
}
func main() {
app := NewApp()
app.lock("locking")
time.Sleep(time.Millisecond * 300)
}
Above code works just fine and panics. If you drop the duration in the main function to 200 * time.Millisecond
, it will not panic and just stop running.