Project

General

Profile

Bug #12607

Ruby needs an atomic integer

Added by shyouhei (Shyouhei Urabe) over 1 year ago. Updated about 1 year ago.

Status:
Feedback
Priority:
Normal
Target version:
-
[ruby-core:76492]

Description

(This one was derived from bug #12463)

Although I don't think += would become atomic, at the same time I understand Rodrigo's needs of easier counter variable that resists inter-thread tampering. I don't think ruby's Integer class can be used for that purpose for reasons (mainly because it is not designed with threads in mind). Rather we should introduce a integer class which is carefully designed.

Why not import Concurrent::AtomicFixnum into core?


Related issues

Related to Ruby trunk - Feature #12463: ruby lacks plus-plusRejected

History

#1 Updated by shyouhei (Shyouhei Urabe) over 1 year ago

#2 [ruby-core:76493] Updated by sawa (Tsuyoshi Sawada) over 1 year ago

Do we want to have another integer variant just after having Fixnum and Bignum been excluded in favor of the Integer class?

#3 [ruby-core:76498] Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 1 year ago

I guess the proper way of helping users to write concurrent code in Ruby is to provide concurrent classes in stdlib rather than relying on third-party gems.

I don't think it makes sense to write something like 1.+=(value) since 1 is immutable. It makes more sense to provide some Counter class to stdlib which would be thread-safe. And a ConcurrentHash and ConcurrentArray. Those alone would already help a lot.

#4 [ruby-core:76681] Updated by sawa (Tsuyoshi Sawada) over 1 year ago

Sorry, I do not clearly understand why the original Integer class cannot be made atomic. If it is not possible or if there would be any problem, can someone explain why that is?

Ideally, I think it would be better if the original Integer class can be modified in some way rather than additional classes being introduced.

#5 [ruby-core:76685] Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 1 year ago

This is not really about Integer handling +=. there's no "+=" method. It's a short-hand syntax: a += 1 is currently expanded to something like "a = a + 1". One proposal is to change it to be expanded to something like "synchronized(a = a + 1)".

Other proposals could offer other concurrent classes so that one would write something like "counter = Counter.new(initial_value)" (0 by default) and "counter.inc(step)" (1 by default). But it doesn't make sense to me to call "count = Integer.new(initial_value)" since Integer instances are constants.

#6 [ruby-core:76813] Updated by shyouhei (Shyouhei Urabe) over 1 year ago

  • Assignee set to ko1 (Koichi Sasada)
  • Status changed from Open to Assigned

I heard from Koichi that he has an opinion on this. Please respond.

#7 [ruby-core:77146] Updated by jwmittag (Jörg W Mittag) over 1 year ago

Tsuyoshi Sawada wrote:

Do we want to have another integer variant just after having Fixnum and Bignum been excluded in favor of the Integer class?

Well, it's not really another integer variant. It's really not a number at all. It's a concurrency primitive (that happens to be a number).

#8 [ruby-core:77966] Updated by ko1 (Koichi Sasada) about 1 year ago

At first, we need a box of integer, not an atomic integer.

Like that:

box = IntegerBox.new(0)
box.increment
box.increment
box.to_i #=> 2

This IntegerBox can be implemented by the following code:

class IntegerBox
  def initialize n
    @n = n
    @m = Mutex.new
  end
  def increment i = 1
    @m.synchonization{ @n += i }
  end
  def to_i
    @n
  end
end

I'm not sure such small part should be include in Ruby's core library.

BTW, concurrent-ruby supports AtomicFixnum http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicFixnum.html.

af = Concurrent::AtomicFixnum.new(0)
af.increment
af.increment
af.value #=> 2

It has update method to set new value. It seems useful.

v = af.value
new_v = v + 5
af.update{ new_v }

But this small code doesn't work as intended.
This is why I think thread-programming is not easy, even if there is cool threading tools.

#9 [ruby-core:77967] Updated by ko1 (Koichi Sasada) about 1 year ago

  • Status changed from Assigned to Feedback

#10 [ruby-core:77968] Updated by shyouhei (Shyouhei Urabe) about 1 year ago

So you mean we don't need atomic integer because concurrent-ruby sucks? I don't think that's a valid reason to reject this.

#11 [ruby-core:77970] Updated by ko1 (Koichi Sasada) about 1 year ago

So you mean we don't need atomic integer because concurrent-ruby sucks? I don't think that's a valid reason to reject this.

I didn't mean that. After "BTW" is only my impression about threading.

#12 [ruby-core:77973] Updated by shyouhei (Shyouhei Urabe) about 1 year ago

OK, then let's discuss the needs of this class.

An obvious benefit of this class to be in core is that we don't even need Mutex in theory. Because we have GVL, if we do this in core we can just increment the backend integer and that should suffice. No overheads must be there. Even when we give up GVL someday in a future, we could still write this using LOCK CMPXCHG or something equivalent. Or JRuby people might want to implement this class using java.util.concurrent.atomic.AtomicLong. Either way, the resulting implementation must be much smarter than the mutex-synchronized pure-ruby implementation.

#13 [ruby-core:77977] Updated by ko1 (Koichi Sasada) about 1 year ago

I agree with performance advantages.

I'm negative to introduce this feature because it is too hard.

People who know well about thread programming can use this feature using concurrent-ruby and I don't want to recommend it for people who don't know about threading well. Also I think such convenient tools can lead misuse. I think using Mutex explicitly is more easy to understand the behavior of application. So I don't want to encourage these by introducing ruby std libs.

Also available in: Atom PDF