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.