在Go中使用互斥锁

I am trying to understand how mutexes work. From my understanding so far, it is made to carry atomic operations and synchronize access to some data.

I built an example of a queue data structure here: https://github.com/arnauddri/algorithms/blob/master/data-structures%2Fqueue%2Fqueue.go

Here is a bit of the code:

package queue

import "sync"

type Queue struct {
    queue []interface{}
    len   int
    lock  *sync.Mutex
}

func New() *Queue {
    queue := &Queue{}
    queue.queue = make([]interface{}, 0)
    queue.len = 0

    return queue
}

func (q *Queue) Push(el interface{}) {
    q.lock.Lock()
    defer q.lock.Unlock()

    q.queue = append(q.queue, el)
    q.len++
}

However when I try to create a queue and push an item to it I get a runtime error:

q := New()
q.Push(1)

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference

I really don't understand what is happening here.

How should I use the Mutex here?

Many thanks

Looks like the issue is that you're never instantiating the mutex. When you run the New() function you're creating an empty Queue with a variable that can reference a mutex, but you never actually tell it to do so, which means that at this point queue.lock == nil. You can fix this by adding in an instantiation line to your New() function.

queue.lock = new(sync.Mutex)

Here is a playground demo that works: http://play.golang.org/p/Qa6buDaHIj

You get that error because you did not allocated any mutex, you have only a pointer to a mutex. Mutex usually are declared inside the structure and without the pointer. See working example below:

http://play.golang.org/p/8LF3yVOkSW

import "sync"

type Queue struct {
    len int

    lock  sync.Mutex // add it before the fields that are being protected by the mutex
    queue []interface{}
}

func New() *Queue {
    queue := &Queue{}
    queue.queue = make([]interface{}, 0)
    queue.len = 0

    return queue
}

func (q *Queue) Push(el interface{}) {
    q.lock.Lock()
    defer q.lock.Unlock()

    q.queue = append(q.queue, el)
    q.len++
}

func main() {
    q := New()
    q.Push(1)
}

Zero value for a pointer is nil, q.lock is a nil pointer, dereference nil pointer will cause panic. You can use lock sync.Mutex instead of *lock sync.Mutex, zero value for a Mutex is an unlocked mutex. Struct anonymous nesting can also solve your problem:

package queue

import "sync"

type Queue struct {
    queue []interface{}
    len   int
    sync.Mutex
}

func New() *Queue {
    queue := &Queue{}
    queue.queue = make([]interface{}, 0)
    queue.len = 0

    return queue
}

func (q *Queue) Push(el interface{}) {
    q.Lock()
    defer q.Unlock()

    q.queue = append(q.queue, el)
    q.len++
}