avoid data races by waiting inside func(s *bState)
This allows ranging over decorators concurrently without using mutexes
or other sync book keeping because next call to d.Decor() is awaited.
Vladimir Bauer
1 year, 10 months ago
| 158 | 158 | |
| 159 | 159 | // TraverseDecorators traverses all available decorators and calls cb func on each. |
| 160 | 160 | func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) { |
| 161 | var wg sync.WaitGroup | |
| 161 | 162 | iter := make(chan decor.Decorator) |
| 162 | 163 | select { |
| 163 | 164 | case b.operateState <- func(s *bState) { |
| 167 | 168 | } |
| 168 | 169 | } |
| 169 | 170 | close(iter) |
| 171 | wg.Wait() | |
| 170 | 172 | }: |
| 171 | 173 | for d := range iter { |
| 172 | cb(unwrap(d)) | |
| 174 | d := d | |
| 175 | go func() { | |
| 176 | cb(unwrap(d)) | |
| 177 | wg.Done() | |
| 178 | }() | |
| 173 | 179 | } |
| 174 | 180 | case <-b.ctx.Done(): |
| 175 | 181 | } |
| 243 | 249 | if current < 0 { |
| 244 | 250 | return |
| 245 | 251 | } |
| 246 | result := make(chan *sync.WaitGroup) | |
| 252 | type item struct { | |
| 253 | decor.EwmaDecorator | |
| 254 | n int64 | |
| 255 | } | |
| 256 | var wg sync.WaitGroup | |
| 257 | iter := make(chan item) | |
| 247 | 258 | select { |
| 248 | 259 | case b.operateState <- func(s *bState) { |
| 249 | 260 | n := current - s.current |
| 261 | wg.Add(len(s.ewmaDecorators)) | |
| 262 | for _, d := range s.ewmaDecorators { | |
| 263 | iter <- item{d, n} | |
| 264 | } | |
| 265 | close(iter) | |
| 250 | 266 | s.current = current |
| 251 | 267 | if s.triggerComplete && s.current >= s.total { |
| 252 | 268 | s.current = s.total |
| 253 | 269 | s.triggerCompletion(b) |
| 254 | 270 | } |
| 255 | var wg sync.WaitGroup | |
| 256 | s.decoratorEwmaUpdate(n, iterDur, &wg) | |
| 257 | result <- &wg | |
| 258 | }: | |
| 259 | wg := <-result | |
| 260 | 271 | wg.Wait() |
| 272 | }: | |
| 273 | for d := range iter { | |
| 274 | d := d | |
| 275 | go func() { | |
| 276 | d.EwmaUpdate(d.n, iterDur) | |
| 277 | wg.Done() | |
| 278 | }() | |
| 279 | } | |
| 261 | 280 | case <-b.ctx.Done(): |
| 262 | 281 | } |
| 263 | 282 | } |
| 299 | 318 | // EwmaIncrInt64 increments progress by amount of n and updates EWMA based |
| 300 | 319 | // decorators by dur of a single iteration. |
| 301 | 320 | func (b *Bar) EwmaIncrInt64(n int64, iterDur time.Duration) { |
| 302 | result := make(chan *sync.WaitGroup) | |
| 303 | select { | |
| 304 | case b.operateState <- func(s *bState) { | |
| 321 | var wg sync.WaitGroup | |
| 322 | iter := make(chan decor.EwmaDecorator) | |
| 323 | select { | |
| 324 | case b.operateState <- func(s *bState) { | |
| 325 | wg.Add(len(s.ewmaDecorators)) | |
| 326 | for _, d := range s.ewmaDecorators { | |
| 327 | iter <- d | |
| 328 | } | |
| 329 | close(iter) | |
| 305 | 330 | s.current += n |
| 306 | 331 | if s.triggerComplete && s.current >= s.total { |
| 307 | 332 | s.current = s.total |
| 308 | 333 | s.triggerCompletion(b) |
| 309 | 334 | } |
| 310 | var wg sync.WaitGroup | |
| 311 | s.decoratorEwmaUpdate(n, iterDur, &wg) | |
| 312 | result <- &wg | |
| 313 | }: | |
| 314 | wg := <-result | |
| 315 | 335 | wg.Wait() |
| 336 | }: | |
| 337 | for d := range iter { | |
| 338 | d := d | |
| 339 | go func() { | |
| 340 | d.EwmaUpdate(n, iterDur) | |
| 341 | wg.Done() | |
| 342 | }() | |
| 343 | } | |
| 316 | 344 | case <-b.ctx.Done(): |
| 317 | 345 | } |
| 318 | 346 | } |
| 573 | 601 | return s.triggerComplete && s.current == s.total |
| 574 | 602 | } |
| 575 | 603 | |
| 576 | func (s bState) decoratorEwmaUpdate(n int64, dur time.Duration, wg *sync.WaitGroup) { | |
| 577 | wg.Add(len(s.ewmaDecorators)) | |
| 578 | for _, d := range s.ewmaDecorators { | |
| 579 | d := d | |
| 580 | go func() { | |
| 581 | d.EwmaUpdate(n, dur) | |
| 582 | wg.Done() | |
| 583 | }() | |
| 584 | } | |
| 585 | } | |
| 586 | ||
| 587 | 604 | func (s bState) newStatistics(tw int) decor.Statistics { |
| 588 | 605 | return decor.Statistics{ |
| 589 | 606 | AvailableWidth: tw, |