paul / progress_bar

A Ruby terminal progress_bar
Do What The F*ck You Want To Public License
623 stars 49 forks source link

When running in multi-threaded environment, @terminal_width sometimes be... #24

Closed ghost closed 10 years ago

ghost commented 10 years ago

When running in multi-threaded environment, @terminal_width sometimes becomes nil.

paul commented 10 years ago

I never tried to run this from different threads, but I'm sure there's a better way to handle this. Do you have a simple test case that exhibits this behavior?

ghost commented 10 years ago

Try to run this several times in the console.

t = []
10.times { t << Thread.new { bar = ProgressBar.new(100, :bar, :percentage, :rate, :elapsed, :eta); 100.times { bar.increment!; sleep(0.01) } } }
t.each(&:join)

The result is this

NoMethodError: undefined method `-' for nil:NilClass
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:143:in `bar_width'
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:100:in `render_bar'
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:92:in `render'
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:77:in `block in to_s'
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:76:in `each'
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:76:in `inject'
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:76:in `to_s'
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:39:in `write'
    from /Users/sergeygoncharov/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/progress_bar-1.0.2/lib/progress_bar.rb:32:in `increment!'
    from (irb):48:in `block (3 levels) in irb_binding'
    from (irb):48:in `times'
    from (irb):48:in `block (2 levels) in irb_binding'
paul commented 10 years ago

I tried that several times in ruby 2.1.2, an grabbed rbx and rubinus to try it there, but am unable to reproduce it at all in irb.

I think the right way to do that is to wrap that ivar in a thread mutex, but I wish I could make it fail to verify that would fix it.

ghost commented 10 years ago

The code above indeed seems to work without any error. I played in the console with different examples before pasting the example and I missed one more required step to replicate it. Here is the full code that fails on both 1.9.3 and 2.1.2

bar = ProgressBar.new(100, :bar, :percentage, :rate, :elapsed, :eta)
t = []
10.times { t << Thread.new { 10.times { bar.increment!; sleep(0.01) } } }
t.each(&:join)
paul commented 10 years ago

Thanks, I was able to reproduce it from that. I've released a 1.0.3 with the fix.