Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync: Lock stuck after a time.Ticker receive #12155

Closed
pierrec opened this issue Aug 15, 2015 · 3 comments
Closed

sync: Lock stuck after a time.Ticker receive #12155

pierrec opened this issue Aug 15, 2015 · 3 comments

Comments

@pierrec
Copy link

pierrec commented Aug 15, 2015

I get the same behaviour with "go1.5rc1 linux/amd64" and "go1.4.2 linux/amd64".

Steps to reproduce

The following program sometimes gets stuck using a bit of CPU (around 40% consistantly):

// Undetected dead lock.
package main

import (
    "fmt"
    "sync"
    "time"
)

type myType struct {
    mu     sync.Mutex
    kill   chan struct{}
    ticker *time.Ticker
}

func New(interval time.Duration) *myType {
    t := &myType{
        kill:   make(chan struct{}),
        ticker: time.NewTicker(interval),
    }
    go func(m *myType) {
        for {
            select {
            case <-m.kill:
                m.ticker.Stop()
                return
            case <-m.ticker.C:
                fmt.Printf("ticker locking\n")
                m.mu.Lock()
                fmt.Printf("tick\n")
                m.mu.Unlock()
                fmt.Printf("ticker unlocked\n")
            }
        }
    }(t)
    return t
}

func (m *myType) Close() {
    fmt.Printf("closing\n")
    m.mu.Lock()
    m.kill <- struct{}{}
    m.mu.Unlock()
    fmt.Printf("closed\n")
}

func main() {
    // Close acquires the lock but the ticker goroutine gets a ticker event
    // and tries to acquire the lock as well: program uses 100% cpu and is stalled
    // using nanoseconds to emphasize the issue
    // got the issue with tickers using 100ms
    m := New(time.Duration(10) * time.Nanosecond)
    // sleeping for a little while helps on go1.5rc1 in reproducing the problem
    time.Sleep(time.Duration(20) * time.Nanosecond)
    m.Close()
}

Expected results

The ticker may or may not print "acquiring lock", "tick", "lock released" without getting stuck trying to get the lock.

Actual results

Depending on the run, one of the following:

  • no output
  • ticker locking
    tick
    ticker unlocked
    closing
    closed
  • closing
    closed
  • closing
    ticker locking

The last output hangs.

Additional information

I purpotedly sleep and tick for a tiny small amount of time to increase the chances of the issue occuring. In my original program, I had a ticker ticking in the range of 100ms to 300ms and had my program sometimes getting stuck for no reason.

@bradfitz
Copy link
Contributor

This is a bug in your program (you're Locking twice, and blocking inside one of your locked regions; make your kill channel buffered). Send SIGQUIT to your program (Control-) to see the deadlock. The deadlock detector is not guaranteed to tell you about everything. It only works for pretty simple cases.

Unlike some projects on Github, we don't use the Go issue tracker for Q&A, since we started with a mailing list. I recommend you post this to golang-nuts@ if you have further questions.

@pierrec
Copy link
Author

pierrec commented Aug 15, 2015

Thanks Brad. It makes sense now, I should have figured it out.
I still think the deadlock detector should have spotted it though :).

@nicolasmendoza
Copy link

+1@bradfitz

@mikioh mikioh changed the title sync.Lock stuck after a time.Ticker receive sync: Lock stuck after a time.Ticker receive Aug 15, 2015
@golang golang locked and limited conversation to collaborators Aug 22, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants