Hi Egon,

I appreciate the effort you've (and everyone has) put in thus-far!

Correct me if I'm wrong, but I think you're pointing out the race condition 
John pointed. That's a tradeoff we've accepted so we don't need to 
reimplement much of http.Serve so that we can add a waitgroup Add or Rlock 
before the goroutine is spawned (among other sync requirements to ensure no 
new connections are accepted, etc).

Thanks again,

Evan



On Tuesday, 13 September 2016 13:11:17 UTC-7, Egon wrote:
>
> On Tuesday, 13 September 2016 22:52:27 UTC+3, Evan Digby wrote:
>>
>> Hi Egon,
>>
>> This is essentially the strategy I'm taking; however, I am hoping to 
>> avoid the "Sleep and Pray" method. Reliable in practice, but not 
>> guaranteed. Also in a CI of thousands of tests, adding time arbitrarily can 
>> extend out the time it takes to test quite a bit.
>>
>> That said, if a sleep is the only way, a sleep is the only way. I hope it 
>> isn't!
>>
>
> You would need to modify the handler to make it work other ways.
> Alternatively you need to write a code-rewriter for injecting code into 
> the handler.
>
> The only reliable concurrent software I've seen is one that is easy to 
> understand, that is backed by a proof (either formal or informal).
>
> I took a deeper look into the taskHandler code -- and it doesn't finish 
> all the tasks before everything:
>
> I.e. 
>
> R1: Line 24 // go func is delayed for some reason
> R2: Line 35 // close is called in main
> R2: Line 36
> R2: Line 37
> R1: Line 25 // go func is started
> R1: Line 28 // task is executed
> R1: Line 26
>
> ATM. too tired to implement a proper solution, will take a look at it 
> tomorrow.
>
> + Egon
>
>
>> Thanks!
>>
>> Evan
>>
>> On Tuesday, 13 September 2016 12:47:40 UTC-7, Egon wrote:
>>>
>>> counter := intr64(N)
>>> release := make(chan struct{})
>>>
>>> ...
>>> for i := 0; i < N; i ++ {
>>>   h.Handle(func() {
>>>       <-release
>>>       atomic.AddInt64(&counter, -1)
>>>   })
>>> }
>>> ...
>>>
>>> go func(){
>>>     time.Sleep(time.Millisecond) // so we would certainly hit h.Close, 
>>> before we continue
>>>     for i := 0; i < N; i++ { release <- struct{}{}; 
>>> time.Sleep(time.Millisecond) }
>>>     // alternatively use runtime.Gosched() instead of Sleep
>>> }()
>>>
>>> h.Close()
>>>
>>> if atomic.LoadInt64(&counter) > 0 {
>>>     // fail
>>> }
>>>
>>> It's not completely fool-proof, but should work well enough in practice.
>>>
>>> On Tuesday, 13 September 2016 21:56:08 UTC+3, Evan Digby wrote:
>>>>
>>>> Has anyone come across a good way, non-racy way to ensure that N tasks 
>>>> are guaranteed to be completed after a function is called? Essentially I 
>>>> have a “Close” function that must be guaranteed to block until all tasks 
>>>> are finished. Achieving this was pretty simple: wrap each task in an 
>>>> RLock, 
>>>> and then a Lock on close. 
>>>>
>>>> Example: https://play.golang.org/p/7lhBPUhkUE
>>>>
>>>> Now I want to write a solid test to guarantee Close will meet that 
>>>> requirement of all tasks must finish first for posterity. In that example, 
>>>> try commenting out the RLock/RUnlock on lines 25/26. You'll see that it no 
>>>> longer outputs many, if any, lines. I'm trying to prevent that from 
>>>> happening in the future by some cowboy refactor!
>>>>
>>>
>>>> All of the ways I can come up with involve Sleeping or launching more 
>>>> tasks than I _think_ can be finished in time--obviously not good!
>>>>
>>>> I feel like I must be missing some obvious way to test this and I'll 
>>>> end up feeling silly once someone replies with the solution. I'm okay with 
>>>> that!
>>>>
>>>

-- 
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