Ah sorry I've missed that in the email.

On Tuesday, August 23, 2016 at 12:48:04 PM UTC+2, T L wrote:
>
>
>
> 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