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