diff --git a/bar.go b/bar.go index 4a11f22..d64e8c5 100644 --- a/bar.go +++ b/bar.go @@ -262,22 +262,18 @@ } } -// Complete signals to the bar, that process has been completed. -// You should call this method when total is unknown and you've reached the point -// of process completion. If you don't call this method, it will be called -// implicitly, upon p.Stop() call. +// Complete stops bar's progress tracking, but not removes the bar. +// If you need to remove, call Progress.RemoveBar(*Bar) instead. func (b *Bar) Complete() { b.once.Do(b.shutdown) + <-b.quit } func (b *Bar) shutdown() { b.quit <- struct{}{} - <-b.quit } func (b *Bar) serve(s *bState, wg *sync.WaitGroup, cancel <-chan struct{}) { - defer wg.Done() - for { select { case op := <-b.operateState: @@ -289,6 +285,7 @@ case <-b.quit: b.cacheState = s close(b.quit) + wg.Done() return } } diff --git a/options.go b/options.go index 60a5b45..175a87c 100644 --- a/options.go +++ b/options.go @@ -42,9 +42,12 @@ } } -// WithRefreshRate overrides default 100ms refresh rate +// WithRefreshRate overrides default 120ms refresh rate func WithRefreshRate(d time.Duration) ProgressOption { return func(s *pState) { + if d < 10*time.Millisecond { + return + } s.ticker.Stop() s.ticker = time.NewTicker(d) s.rr = d diff --git a/progress.go b/progress.go index af3b43e..3597b0b 100644 --- a/progress.go +++ b/progress.go @@ -157,14 +157,14 @@ if p.ewg != nil { p.ewg.Wait() } - // wait for all bars to quit + // first wait for all bars to quit p.wg.Wait() p.once.Do(p.shutdown) + <-p.quit } func (p *Progress) shutdown() { p.quit <- struct{}{} - <-p.quit } func newWidthSync(timeout <-chan struct{}, numBars, numColumn int) *widthSync { @@ -206,7 +206,7 @@ func (s *pState) writeAndFlush(tw, numP, numA int) (err error) { wSyncTimeout := make(chan struct{}) - time.AfterFunc(s.rr, func() { + time.AfterFunc(s.rr-s.rr/12, func() { close(wSyncTimeout) }) diff --git a/progress_posix.go b/progress_posix.go index a32723b..bfa2eef 100644 --- a/progress_posix.go +++ b/progress_posix.go @@ -61,6 +61,7 @@ s.cancel = nil // don't return here, p.Stop() must be called eventually case <-p.quit: + close(p.quit) if s.cancel != nil { s.ticker.Stop() } @@ -68,7 +69,6 @@ close(s.shutdownNotifier) } signal.Stop(winch) - close(p.quit) return } } diff --git a/progress_test.go b/progress_test.go index a49328f..6168520 100644 --- a/progress_test.go +++ b/progress_test.go @@ -51,6 +51,38 @@ p.Stop() } +func TestRemoveBars(t *testing.T) { + p := mpb.New(mpb.Output(ioutil.Discard)) + + var wg sync.WaitGroup + bars := make([]*mpb.Bar, 3) + for i := 0; i < 3; i++ { + wg.Add(1) + b := p.AddBar(80) + bars[i] = b + go func() { + for i := 0; i < 80; i++ { + if i == 33 { + wg.Done() + } + b.Increment() + time.Sleep(randomDuration(80 * time.Millisecond)) + } + }() + } + + wg.Wait() + for i := 0; i < 3; i++ { + i := i + go func() { + if ok := p.RemoveBar(bars[i]); !ok { + t.Errorf("bar %d: remove failed\n", i) + } + }() + } + p.Stop() +} + func TestWithCancel(t *testing.T) { var wg sync.WaitGroup cancel := make(chan struct{}) @@ -79,7 +111,7 @@ return default: } - time.Sleep(time.Duration(rand.Intn(10)+1) * time.Second / 100) + time.Sleep(randomDuration(80 * time.Millisecond)) bar.Increment() } }() @@ -107,16 +139,21 @@ mpb.WithCancel(cancel), mpb.WithFormat(customFormat), ) - bar := p.AddBar(100, mpb.BarTrim()) + bar := p.AddBar(80, mpb.BarTrim()) + var wg sync.WaitGroup + wg.Add(1) go func() { - for i := 0; i < 100; i++ { - time.Sleep(10 * time.Millisecond) + for i := 0; i < 80; i++ { + if i == 33 { + wg.Done() + } + time.Sleep(randomDuration(80 * time.Millisecond)) bar.Increment() } }() - time.Sleep(300 * time.Millisecond) + wg.Wait() close(cancel) p.Stop() @@ -139,7 +176,7 @@ bar := p.AddBar(100, mpb.BarTrim()) for i := 0; i < 100; i++ { - time.Sleep(10 * time.Millisecond) + time.Sleep(randomDuration(40 * time.Millisecond)) bar.Increment() } @@ -151,3 +188,7 @@ t.Errorf("Expected format: %s, got %s\n", want, got) } } + +func randomDuration(max time.Duration) time.Duration { + return time.Duration(rand.Intn(10)+1) * max / 10 +} diff --git a/progress_windows.go b/progress_windows.go index b3f8ab0..f9a18ba 100644 --- a/progress_windows.go +++ b/progress_windows.go @@ -38,13 +38,13 @@ s.cancel = nil // don't return here, p.Stop() must be called eventually case <-p.quit: + close(p.quit) if s.cancel != nil { s.ticker.Stop() } if s.shutdownNotifier != nil { close(s.shutdownNotifier) } - close(p.quit) return } }