Structures / mutex question

66 views
Skip to first unread message

Slawomir Pryczek

unread,
Oct 9, 2022, 7:48:45 AM10/9/22
to golang-nuts
Hi Guys,
wanted to see if i making correct assumptions regarding mutexes and structures

var globalMutex sync.Mutex{}
type abc struct {
    a int
    b int
    mu sync.Mutex{}
}

1. First is self explanatory, array of structures all needs to be protected by mutex
x := []abc{}
x = append(x, abc{})  // <- This needs to be done inside globalMutex.Lock
x[0].a = 10 // <- This needs to be done inside globalMutex.Lock, as the array/slice is holding the data (?)
- Reading x[0].a would require globalMutex.RLock
- Mu is not necessary

2. Array of pointer to structures
y := []*abc{}
_tmp := &abc{}
y = append(y, _tmp)   <- This needs to be put inside globalMutex.Lock Mutex
 y[0].b = 1  <- This can be put inside  globalMutex.RLock and we also need mu.Lock (as it's sufficient to read abc pointer and the pointer will never change after the element gets added to the list)
- Reading y[0].b would require RLock on both globalMutex and mu

Or maybe it's better to just use generic read-write locks for everything and don't bother?

Thanks






burak serdar

unread,
Oct 9, 2022, 12:38:36 PM10/9/22
to Slawomir Pryczek, golang-nuts
On Sun, Oct 9, 2022 at 5:49 AM Slawomir Pryczek <slawe...@gmail.com> wrote:
Hi Guys,
wanted to see if i making correct assumptions regarding mutexes and structures

var globalMutex sync.Mutex{}
type abc struct {
    a int
    b int
    mu sync.Mutex{}
}

1. First is self explanatory, array of structures all needs to be protected by mutex
x := []abc{}
x = append(x, abc{})  // <- This needs to be done inside globalMutex.Lock

There are some things to consider for this usage. You need the global mutex to lock the slice when appending. If append needs to reallocate a new slice, using a *sync.Mutex will work, but any goroutines working on the elements of the slice will be working on stale copies of it. That is, if one goroutine appends to the slice while another is modifying its elements, the modification to the elements may be lost in the new copy of the slice.

In short: you should not use struct abc as value if you're ever going to append to the slice.

If you are not going to append, then embed *sync.Mutex, otherwise you will be copying the mutex.
 
x[0].a = 10 // <- This needs to be done inside globalMutex.Lock, as the array/slice is holding the data (?)

In general, you can lock x[0] for this without locking the global mutex, so other goroutines can update other elements of the array. This, if only you are not appending to the slice.
 
- Reading x[0].a would require globalMutex.RLock

It would require x[0].RLock(), if you are not appending to the slice.
 

- Mu is not necessary

You can do this with a global mutex, but that will prevent concurrency for goroutines working on different slice elements.
 

2. Array of pointer to structures
y := []*abc{}
_tmp := &abc{}
y = append(y, _tmp)   <- This needs to be put inside globalMutex.Lock Mutex

The above is correct.
 
 y[0].b = 1  <- This can be put inside  globalMutex.RLock and we also need mu.Lock (as it's sufficient to read abc pointer and the pointer will never change after the element gets added to the list)

You don't need to rlock the global mutex. Even if another goroutine appends to the slice and slice gets reallocated, this code will still be pointing to the correct element.
 
- Reading y[0].b would require RLock on both globalMutex and mu

It would require rlock on y[0] only.
 

Or maybe it's better to just use generic read-write locks for everything and don't bother?

Thanks






--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/ffc7c10e-ddb9-4bc5-a545-2a1ce7b22bfbn%40googlegroups.com.

Slawomir Pryczek

unread,
Oct 9, 2022, 2:44:11 PM10/9/22
to golang-nuts
Thanks, very good point about including the structure by-value.

As for using the structure via pointer

> You don't need to rlock the global mutex. Even if another goroutine appends to
> the slice and slice gets reallocated, this code will still be pointing to the correct element.

I'd assume I'll still need the global RLock, as len will not be synchronized. And moreover if i shrink the array by 1 and then append one element, i'll be changing the pointer in-place which could result in some pseudo-random memory location being accessed.

burak serdar

unread,
Oct 9, 2022, 3:22:17 PM10/9/22
to Slawomir Pryczek, golang-nuts
On Sun, Oct 9, 2022 at 12:44 PM Slawomir Pryczek <slawe...@gmail.com> wrote:
Thanks, very good point about including the structure by-value.

As for using the structure via pointer

> You don't need to rlock the global mutex. Even if another goroutine appends to
> the slice and slice gets reallocated, this code will still be pointing to the correct element.

I'd assume I'll still need the global RLock, as len will not be synchronized. And moreover if i shrink the array by 1 and then append one element, i'll be changing the pointer in-place which could result in some pseudo-random memory location being accessed.

If you create a goroutine and work with one of the elements of the slice of pointers, you will not need to rlock the global mutex. If that goroutine accesses the slice itself, then yes, you'll need it. 
 
Reply all
Reply to author
Forward
0 new messages