pigfox
pigfox

Reputation: 1401

Mutex not locking

I noticed some unexpected behavior when using Mutex so I decided to write some test code.

package main

import (
    "fmt"
    "sync"
)

type Box struct {
    Stuff int
    mu    sync.Mutex
}

var box Box

func init() {
    box = Box{}
    box.mu.Lock()
}

func (box *Box) add() {
    fmt.Println("add()")
    box.mu.Unlock()
    box.Stuff++
    box.mu.Lock()
}

func (box *Box) display() {
    fmt.Print("display(): ")
    box.mu.Unlock()
    fmt.Println(box.Stuff)
    box.mu.Lock()
}

func add2() {
    fmt.Println("add2()")
    box.Stuff++ //increments but should not, error expected
}

func display2() {
    fmt.Print("display2(): ")
    fmt.Println(box.Stuff) //displays but should not, error expected
}

func main() {
    box.display()
    box.add()
    box.display()
    display2()
    add2()
    box.display()
}

The functions without pointer receivers can add & access the protected struct. Running the code.

display(): 0
add()
display(): 1
display2(): 1
add2()
display(): 2

I would expect the two functions which have the name appended with a 2 to fail. They do not.

Any idea?

Upvotes: 0

Views: 71

Answers (1)

Norbert
Norbert

Reputation: 6084

You might want to write this a bit different:

You start by locking, which is not the most common way to use a lock: Everything is locked unless you unlock it.

A more common way is:

package main

import (
    "fmt"
    "sync"
)

type Box struct {
    Stuff int
    mu    sync.Mutex
}

var box Box

func init() {
    box = Box{}
}

func (box *Box) add() {
    fmt.Println("add()")
    box.mu.Lock()
    box.Stuff++
    box.mu.Unlock()
}
...

Scoping your locks to the moment of change and not to the complete app.

Upvotes: 3

Related Questions