Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using mutexes in Go

Tags:

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

like image 293
Spearfisher Avatar asked Jan 30 '15 19:01

Spearfisher


People also ask

What is mutex lock in Go?

A Mutex is a method used as a locking mechanism to ensure that only one Goroutine is accessing the critical section of code at any point of time. This is done to prevent race conditions from happening. Sync package contains the Mutex.

What is sync in Golang?

We can make use of channels if we want to synchronize goroutines. By synchronizing, we want to make the goroutines work in a defined manner, for example, not starting the next goroutine until the previous one has finished its execution.


2 Answers

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)
}
like image 115
fabrizioM Avatar answered Nov 15 '22 08:11

fabrizioM


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

like image 39
Verran Avatar answered Nov 15 '22 08:11

Verran