On Tuesday, August 23, 2016 at 6:14:19 PM UTC+8, Yulrizka wrote:
>
> Thank you for the explanation and the code sample
>
> But the case here is indeed as Marvin explained, There is race condition. 
>

Marvin says there is no race condition in your start comment.
 

> But in my example, I make sure that wg done is to protect result pointer 
> before calling it to caller. 
>
> with this structure some one could easily introduce a race condition if he 
> tried to access the result pointer.
>
> What I would like to understand if there is case that my snippet causes 
> race condition.
>
> This is my understanding.
> 1. Heap memory is shared between go rountine in the same process
> 2. main routine create a pointer to some struct on the heap (initially nil)
> 3. the go routine allocate memory on the heap for the `foo` struct
> 4. the go routine assign main's result pointer
> 5. wg.Done() ensure that step 4 is done before it released
> 6. process will always returns value generated by the go routine.
>
> And I would like to make sure that my understanding of heap is correct. 
> That is shared per process and there are no heap copying between go routine.
>
> Thanks for the response so far, It is really interesting discussion for me 
> :)
>
> On Monday, August 22, 2016 at 3:47:03 PM UTC+2, Joubin Houshyar wrote:
>>
>>
>>
>> On Saturday, August 20, 2016 at 2:29:41 AM UTC-4, Yulrizka wrote:
>>>
>>> Dear gophers
>>>
>>> I have discussion with my colleague about this code
>>>
>>>
>>> func process() *foo {
>>>     var result *foo
>>>
>>>     var wg sync.WaitGroup
>>>     wg.Add(1)
>>>     go func() {
>>>         defer wg.Done()
>>>         result = &foo{1}
>>>     }()
>>>
>>>     wg.Wait()
>>>
>>>     return result
>>> }
>>>
>>> He argues that this is heap race condition. 
>>> the result variable which lives on the heap of the go routine is not 
>>> guaranteed to be synced to the result on the process func's thread.
>>> The better approach would be using a channel instead. I may agree with 
>>> him that probably using channel is better.
>>> But I would like to understand the reasoning behind that.
>>>
>>> I thought that `wg.Wait()` guaranteed that the process func's thread 
>>> wait until go func is finsihed and sync everything so that the result 
>>> variable is safe to return.
>>>
>>> Probably I'm missing some knowledge about how go routine work.
>>>
>>> 1. Does the process func thread has separate heap than the go func? If 
>>> so how does is sync?
>>> 2. From I read so far, when go routine needed a bigger stack, it 
>>> allocates memory from the heap. So what happened for object that is 
>>> allocated inside of the go routine once the go routine returns?
>>>
>>> I there article of source that go into details about this I would love 
>>> to read it :)
>>>
>>> Warm regards,
>>>
>>
>> Your firend is correct that using a WaitGroup here does not in anyway 
>> address concurrent access to the heap variable 'result'. 
>>
>> This modified example should clear it up:
>>
>> package main
>>
>> import (
>>     "fmt"
>>     "sync"
>> )
>>
>> func main() {
>>     var i int
>>     for {
>>         r := process()
>>         if r.v == 8 {
>>             fmt.Printf("%d\n", i)
>>             panic("eight!")
>>         }
>>         i++
>>     }
>> }
>>
>> type foo struct {
>>     v int
>> }
>>
>> func process() *foo {
>>     var result *foo
>>     var wg sync.WaitGroup
>>
>>     wg.Add(1)
>>     go func() {
>>         defer wg.Done()
>>         result = &foo{1}
>>     }()
>>
>>     // race condition on result
>>     result = &foo{8}
>>
>>     wg.Wait()
>>     return result
>> }
>>
>> The issue here is the runtime scheduler and what execution order can 
>> occur before the go routine execution 'process' has been stopped at 
>> wg.Wait. So process can return a foo initiazed with either 1 or 8. 
>>
>> I think the general Go developer intuiton here is that the go routine 
>> will not run until the parent go routine has hit the wg.Wait (since there 
>> are no explicit IO or blocking instructions between the go func() and 
>> wg.Wait. However, using Go(1.7) the main loop will panic after as little as 
>> 1000 loops.
>>
>>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to