Should we synchronize on writing strings? Since string is immutable we will never get inconsistent state between write and read from the 2 different threads, right?
On other words, why we don't have atomic for string type?
Should we synchronize on writing strings? Since string is immutable we will never get inconsistent state between write and read from the 2 different threads, right?
On other words, why we don't have atomic for string type?
All functions defined on String type at language syntax level or in standard library return a new string instance. No one function mutate string in-place. Just follow this practice and you will be concurrently-safe.
string
values are immutable, but variables are not. Variables are–what their name say–variable, their values can be changed.You don't need synchronization for accessing a
string
value, that can't change. If astring
value is handed to you, that (the content of thestring
) will always remain the same (usage of packageunsafe
does not count).You need synchronization when you want to access a variable of
string
type from multiple goroutines concurrently, if at least one of the accesses is a write (a write that changes the value of thestring
variable). This is true for variables of any type in Go, thestring
type is not special in any way.What does this mean in practice?
If you have a function that receives a
string
value"hello"
, you can be sure thestring
value will stay"hello"
no matter what. Consequently if you don't change the argument yourself (e.g. you don't assign a new value to it), it will always hold thestring
value"hello"
.As a counter-example, if your function receives a slice value
[]byte{1, 2, 3}
, you don't have the same guarantee, because slices are mutable. The caller also has the slice value (the slice header), else it couldn't pass it in the first place. And if the caller modifies the elements of the slice concurrently, since they share the same backing array, the slice that was handed to you will also see the changed data... with proper synchronization; because without synchronization this would be a data race (and hence undefined behavior).See this example:
Output (try it on the Go Playground):
Focus on
sliceTest()
: it receives a slice, and it prints it. Then waits a little (gives a "go" to a concurrent goroutine to modify it, and waits for this modification to complete), and prints it again, and it has changed, yetsliceTest()
itself did not modify it.Now if
sliceTest()
would receive astring
argument instead, this could not happen.See related / possible duplicate: Immutable string and pointer address
That's the question. The answer is: synchronize on writing strings. It's clear that
string
variables are mutable andstring
contents are immutable, as I already explained earlier. To reiterate:The Go compiler will enforce the immutability of
string
contents. For example,Output:
The Go runtime Data Race Detector flags the inconsistent state of mutable
string
variables updated from different goroutines. For example, writing to astring
variable,Output:
Original Post:
A
string
variable is not immutable. It contains a string descriptor, astruct
.For example,
Output:
The
string
contents are immutable. For example,You need synchronization for access to string variables.