Is it safe when one goroutine writes a string and the other goroutines read it without lock?

2,926 views
Skip to first unread message

吴延毅

unread,
Feb 3, 2015, 10:24:41 AM2/3/15
to golan...@googlegroups.com
I think it needs `sync.RWMutex` to gurantee its concurrency-safety in this case.
The author say something about (copy-on-write), I don't know what is the relationship between them.

Anyone else can help me? 

Jan Mercl

unread,
Feb 3, 2015, 10:40:14 AM2/3/15
to 吴延毅, golan...@googlegroups.com
On Tue Feb 03 2015 at 16:24:51 吴延毅 <wuya...@gmail.com> wrote:

> Anyone else can help me? 

If one goroutine mutates a thing and concurrently another goroutine reads the same bytes mutated by it without any synchronization, it's a data race and anything can happen. No exceptions even though on some architectures one can abuse the fact that some stores/loads might be invariably atomic without asking for that. However, the same code on a different machine can fail.

Synchronization can be achieved for example by using sync/atomic primitives or via critical sections (sync.Mutex, sync.RWMutex, user written semaphores, ...).

It doesn't matter if the mutated thing is or is not a string variable, string struct field etc. Only the backing array of s string is immutable and thus immune to race conditions.

-j

Dmitry Vyukov

unread,
Feb 3, 2015, 10:43:49 AM2/3/15
to 吴延毅, golang-nuts
This is a bad data race that can lead to memory corruption and
arbitrary consequences.
When in doubt, use the race detector:
$ go build/test/run -race your_pkg
> --
> 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.
> For more options, visit https://groups.google.com/d/optout.

ed...@bit-delta-one.com

unread,
Feb 3, 2015, 10:51:12 AM2/3/15
to golan...@googlegroups.com
the idiomatic GO way is to use a channel to pass the mutated value between the goroutines.   

ChrisLu

unread,
Feb 4, 2015, 3:13:42 AM2/4/15
to golan...@googlegroups.com, wuya...@gmail.com
Don't jump into conclusion so quickly. I am the author the OP referred to. The use case is this:

One goroutine set one value x = "some_new_value" during a rare state transition, which usually takes 10s of seconds.
Other goroutines acts on value x, and fails if something wrong. But the failure is expected during the transition period.

Given the use case, I do not feel the need to add extra locks, channels etc. Simpler code is better. 

Chris

Dmitry Vyukov

unread,
Feb 4, 2015, 3:32:10 AM2/4/15
to ChrisLu, golang-nuts, 吴延毅
On Wed, Feb 4, 2015 at 11:13 AM, ChrisLu <chri...@gmail.com> wrote:
> Don't jump into conclusion so quickly. I am the author the OP referred to.
> The use case is this:
>
> One goroutine set one value x = "some_new_value" during a rare state
> transition, which usually takes 10s of seconds.
> Other goroutines acts on value x, and fails if something wrong. But the
> failure is expected during the transition period.
>
> Given the use case, I do not feel the need to add extra locks, channels etc.
> Simpler code is better.


If you feel that it is OK for your program to crash, send out
passwords and delete files, then it is up to you.


> On Tuesday, February 3, 2015 at 7:40:14 AM UTC-8, Jan Mercl wrote:
>>
>> On Tue Feb 03 2015 at 16:24:51 吴延毅 <wuya...@gmail.com> wrote:
>>
>> > Anyone else can help me?
>>
>> If one goroutine mutates a thing and concurrently another goroutine reads
>> the same bytes mutated by it without any synchronization, it's a data race
>> and anything can happen. No exceptions even though on some architectures one
>> can abuse the fact that some stores/loads might be invariably atomic without
>> asking for that. However, the same code on a different machine can fail.
>>
>> Synchronization can be achieved for example by using sync/atomic
>> primitives or via critical sections (sync.Mutex, sync.RWMutex, user written
>> semaphores, ...).
>>
>> It doesn't matter if the mutated thing is or is not a string variable,
>> string struct field etc. Only the backing array of s string is immutable and
>> thus immune to race conditions.
>>
>> -j
>>

Caleb Spare

unread,
Feb 4, 2015, 3:36:45 AM2/4/15
to ChrisLu, golang-nuts, wuya...@gmail.com

Caleb Spare

unread,
Feb 4, 2015, 3:40:10 AM2/4/15
to ChrisLu, golang-nuts, wuya...@gmail.com
If you want to do copy-on-write correctly according to the Go memory model, here's one example:


On Wed, Feb 4, 2015 at 12:13 AM, ChrisLu <chri...@gmail.com> wrote:

ChrisLu

unread,
Feb 4, 2015, 4:12:32 AM2/4/15
to golan...@googlegroups.com, chri...@gmail.com, wuya...@gmail.com
Thanks for the helpful links. I want to find out the answer to this question:

One goroutine changes value x to "some_new_string_value".
Are there cases that some other goroutine will never read the new value in x?

Chris

Jan Mercl

unread,
Feb 4, 2015, 4:22:44 AM2/4/15
to golan...@googlegroups.com
On Wed Feb 04 2015 at 10:12:39 ChrisLu <chri...@gmail.com> wrote:

> One goroutine changes value x to "some_new_string_value".
> Are there cases that some other goroutine will never read the new
> value in x?

The other goroutine concurrently reading the variable can, for example

- read the old value.
- read the new value.
- read no value and instead crash the program with segfault.
- read any value, which passed on can later, when used/accessed, make the application to do things it's not supposed/safe to do and/or segfault.
- nuke a random country.
- etc.

-j

Dmitry Vyukov

unread,
Feb 4, 2015, 4:30:12 AM2/4/15
to ChrisLu, golang-nuts, 吴延毅
On Wed, Feb 4, 2015 at 12:12 PM, ChrisLu <chri...@gmail.com> wrote:
> Thanks for the helpful links. I want to find out the answer to this
> question:
>
> One goroutine changes value x to "some_new_string_value".
> Are there cases that some other goroutine will never read the new value in
> x?


Yes, the goroutine will never read the new value of x, it it crashes
while reading intermediate value.
If there is no synchronization, then value of x can also be cached in
registers and never actually re-read from shared memory.

Chris Lu

unread,
Feb 4, 2015, 4:50:05 AM2/4/15
to Dmitry Vyukov, golang-nuts, 吴延毅
> Thanks for the helpful links. I want to find out the answer to this
> question:
>
> One goroutine changes value x to "some_new_string_value".
> Are there cases that some other goroutine will never read the new value in
> x?


Yes, the goroutine will never read the new value of x, it it crashes
while reading intermediate value.
If there is no synchronization, then value of x can also be cached in
registers and never actually re-read from shared memory.


Hope I can use something similar to Java's "volatile" keyword to avoid these ceremonial code.

Alright..., it's against some Golang philosophy?...

Chris

Dmitry Vyukov

unread,
Feb 4, 2015, 5:10:38 AM2/4/15
to Chris Lu, golang-nuts, 吴延毅
As was mentioned above, sync/atomic.Value is what you are looking for.

Also run tests and test the program with -race flag, it will point to
any data races.

roger peppe

unread,
Feb 4, 2015, 6:47:19 AM2/4/15
to Chris Lu, Dmitry Vyukov, golang-nuts, 吴延毅
If performance isn't an issue (and it sounds like it probably is not
in your case)
then just use a sync.Mutex. It gives a warning to anyone reading the code
that the value is concurrently changed and it really is not much code to
write.

Chandru

unread,
Feb 4, 2015, 8:04:12 AM2/4/15
to Dmitry Vyukov, golang-nuts
Is there any case where the race detector can miss a data race, even though it occurred during the execution of the program?

--
Chandra Sekar.S

Dmitry Vyukov

unread,
Feb 4, 2015, 8:27:57 AM2/4/15
to Chandru, golang-nuts
On Wed, Feb 4, 2015 at 4:03 PM, Chandru <chand...@gmail.com> wrote:
> Is there any case where the race detector can miss a data race, even though
> it occurred during the execution of the program?


It depends on what you call a data race.

Chandru

unread,
Feb 4, 2015, 8:31:56 AM2/4/15
to Dmitry Vyukov, golang-nuts
Same region of memory mutated concurrently without any synchronization is what I was thinking of. Not cases like existence check and insertion to a map being locked independently.

--
Chandra Sekar.S

Dmitry Vyukov

unread,
Feb 4, 2015, 8:46:28 AM2/4/15
to Chandru, golang-nuts
Some false negatives are possible under obscure conditions.
But false positives should be one-shot, and detected after several
runs of the program.
Reply all
Reply to author
Forward
0 new messages