在Go中使用互斥锁

时间:2015-01-30 19:41:32

标签: go

我试图了解互斥量的工作原理。根据我的理解,到目前为止,它可以进行原子操作并同步访问某些数据。

我在这里建立了一个队列数据结构的例子:https://github.com/arnauddri/algorithms/blob/master/data-structures%2Fqueue%2Fqueue.go

以下是一些代码:

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++
}

然而,当我尝试创建一个队列并将项目推送到它时,我收到一个运行时错误:

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

我真的不明白这里发生了什么。

我应该如何在这里使用Mutex?

非常感谢

3 个答案:

答案 0 :(得分:11)

您收到该错误是因为您没有分配任何互斥锁,只有指向互斥锁的指针。 互斥体通常在结构内声明,没有指针。见下面的工作示例:

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)
}

答案 1 :(得分:1)

看起来问题是你永远不会实例化互斥锁。当您运行New()函数时,您正在创建一个带有可引用互斥锁的变量的空队列,但您实际上并没有告诉它这样做,这意味着此时queue.lock == nil。您可以通过在New()函数中添加实例化行来解决此问题。

queue.lock = new(sync.Mutex)

这是一个有效的游乐场演示:http://play.golang.org/p/Qa6buDaHIj

答案 2 :(得分:1)

指针的零值是nil,q.lock是nil指针,dereference nil指针会引起恐慌。 您可以使用 lock sync.Mutex 而不是 * lock sync.Mutex ,Mutex的零值是解锁的互斥锁。 结构匿名嵌套也可以解决您的问题:

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++
}