Difference between value type and reference type of lock in golang

introduce Mutex into the object to ensure atomicity, but when the object is a value reference, it is found that the cable has no effect. What is its internal implementation logic?

the code is as follows:

package main

import (
    "fmt"
    "sync"
)

//
type people struct {
    sync.Mutex
}

//
func (p people) test(str string) {
    p.Lock();
    defer p.Unlock();

    for i := 0; i < 5; {
        fmt.Println(str, i)
        iPP
    }
}

func main() {
    var user people
    var wg sync.WaitGroup

    wg.Add(2)
    go func() {
        defer wg.Done()
        user.test("go1")
    }()

    go func() {
        defer wg.Done()
        user.test("go2")
    }()

    wg.Wait()
}

if executed in this way, you can"t see the effect, and then add this line of code:

func (p people) test(str string) {
    p.Lock();
    defer p.Unlock();

    for i := 0; i < 5; {
        fmt.Println(str, i)
        
        //
        time.Sleep(time.Second)
        iPP
    }
}

the result of discovery execution is as follows:

go2 0
go1 0
go2 1
go1 1
go1 2
go2 2
go2 3
go1 3
go1 4
go2 4

puzzling point: in the whole logic process, there is only one variable user, that does not copy the value, so how can the good lock not take effect?

Feb.27,2021

func (p *people) test(str string) {
    // balabala
}

first of all, mutex cannot be copied. Once mutex is copied, locked and unlocked on different mutex objects, it naturally loses its effect.

in addition, for the receiving object of a method, there is an essential difference between a value and a pointer:
1. When a function call is made when the receiver is a pointer, the pointer to the object is passed.
2. When the receiver is a value, the function call passes a copy of the value.
this can be verified by changing the value of the object in the function call.

therefore, when the people object makes a function call, the people has copied the new value and generated a new mutex, so the lock is invalid. Here, change the recipient of the test method to * people.


try to write code: it's exactly what you said. So let me sum up:

  1. for a method called on a value, a copy of the object is made in the body of the method, which cannot be saved and is released after the method call ends. Therefore, if you want the object in the body of the method to save the new changes, you need to use a reference call.
  2. in the following code, a user, declared only by an object cannot be understood as an object, but rather as a form of invocation. Of course, it's just a type function for a value declaration.
func (p people) getAge() int  {
    return p.age
}

func (p people) setAge(newAge int)  {
    p.age = newAge
    fmt.Println("copy a object. age ", p.age)
}

func main() {
    var user people
    user.setAge(1)
    fmt.Println(user.getAge())
}
Menu