File: volatile.rb

package info (click to toggle)
ruby-concurrent 1.1.6%2Bdfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 30,284 kB
  • sloc: ruby: 30,875; java: 6,117; javascript: 1,114; ansic: 288; makefile: 10; sh: 6
file content (75 lines) | stat: -rw-r--r-- 2,330 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
require 'concurrent/thread_safe/util'

module Concurrent

  # @!visibility private
  module ThreadSafe

    # @!visibility private
    module Util
      
      # @!visibility private
      module Volatile

        # Provides +volatile+ (in the JVM's sense) attribute accessors implemented
        # atop of +Concurrent::AtomicReference+.
        #
        # Usage:
        #   class Foo
        #     extend Concurrent::ThreadSafe::Util::Volatile
        #     attr_volatile :foo, :bar
        #
        #     def initialize(bar)
        #       super() # must super() into parent initializers before using the volatile attribute accessors
        #       self.bar = bar
        #     end
        #
        #     def hello
        #       my_foo = foo # volatile read
        #       self.foo = 1 # volatile write
        #       cas_foo(1, 2) # => true | a strong CAS
        #     end
        #   end
        def attr_volatile(*attr_names)
          return if attr_names.empty?
          include(Module.new do
            atomic_ref_setup = attr_names.map {|attr_name| "@__#{attr_name} = Concurrent::AtomicReference.new"}
            initialize_copy_setup = attr_names.zip(atomic_ref_setup).map do |attr_name, ref_setup|
              "#{ref_setup}(other.instance_variable_get(:@__#{attr_name}).get)"
            end
            class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
            def initialize(*)
              super
            #{atomic_ref_setup.join('; ')}
            end

            def initialize_copy(other)
              super
            #{initialize_copy_setup.join('; ')}
            end
            RUBY_EVAL

            attr_names.each do |attr_name|
              class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
              def #{attr_name}
                @__#{attr_name}.get
              end

              def #{attr_name}=(value)
                @__#{attr_name}.set(value)
              end

              def compare_and_set_#{attr_name}(old_value, new_value)
                @__#{attr_name}.compare_and_set(old_value, new_value)
              end
              RUBY_EVAL

              alias_method :"cas_#{attr_name}", :"compare_and_set_#{attr_name}"
              alias_method :"lazy_set_#{attr_name}", :"#{attr_name}="
            end
          end)
        end
      end
    end
  end
end