concurrent-ruby 1.1.10 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -1
  3. data/Gemfile +1 -2
  4. data/README.md +23 -20
  5. data/Rakefile +75 -65
  6. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  7. data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
  8. data/lib/concurrent-ruby/concurrent/array.rb +3 -13
  9. data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
  10. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
  11. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
  12. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
  13. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +81 -151
  14. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
  15. data/lib/concurrent-ruby/concurrent/atomic/event.rb +1 -1
  16. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  17. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
  18. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
  19. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
  20. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
  21. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
  22. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
  23. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +1 -1
  24. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
  25. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +5 -3
  26. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +6 -9
  27. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
  28. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  29. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
  30. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
  31. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
  32. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
  33. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +2 -2
  34. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +16 -8
  35. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +23 -20
  36. data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
  37. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  38. data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
  39. data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
  40. data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
  41. data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
  42. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +1 -1
  43. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +4 -0
  44. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +6 -9
  45. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +5 -0
  46. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +7 -0
  47. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +1 -1
  48. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
  49. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
  50. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +6 -2
  51. data/lib/concurrent-ruby/concurrent/hash.rb +5 -12
  52. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
  53. data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
  54. data/lib/concurrent-ruby/concurrent/map.rb +43 -39
  55. data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
  56. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
  57. data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
  58. data/lib/concurrent-ruby/concurrent/promise.rb +1 -1
  59. data/lib/concurrent-ruby/concurrent/promises.rb +40 -29
  60. data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
  61. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +1 -1
  62. data/lib/concurrent-ruby/concurrent/set.rb +0 -10
  63. data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
  64. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
  65. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
  66. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
  67. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  68. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
  69. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
  70. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +5 -2
  71. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +6 -5
  72. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
  73. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  74. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
  75. data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
  76. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
  77. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +1 -37
  78. data/lib/concurrent-ruby/concurrent/timer_task.rb +59 -9
  79. data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
  80. data/lib/concurrent-ruby/concurrent/tvar.rb +2 -1
  81. data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
  82. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +3 -74
  83. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
  84. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
  85. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +118 -58
  86. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  87. metadata +13 -17
  88. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  89. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
  90. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
  91. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +0 -927
  92. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
  93. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
  94. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -71
  95. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
  96. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
  97. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +0 -118
@@ -1,102 +1,19 @@
1
1
  require 'thread'
2
2
  require 'concurrent/delay'
3
3
  require 'concurrent/errors'
4
- require 'concurrent/atomic/atomic_reference'
5
- require 'concurrent/concern/logging'
6
4
  require 'concurrent/concern/deprecation'
7
5
  require 'concurrent/executor/immediate_executor'
6
+ require 'concurrent/executor/fixed_thread_pool'
8
7
  require 'concurrent/executor/cached_thread_pool'
9
8
  require 'concurrent/utility/processor_counter'
10
9
 
11
10
  module Concurrent
12
- extend Concern::Logging
13
11
  extend Concern::Deprecation
14
12
 
15
13
  autoload :Options, 'concurrent/options'
16
14
  autoload :TimerSet, 'concurrent/executor/timer_set'
17
15
  autoload :ThreadPoolExecutor, 'concurrent/executor/thread_pool_executor'
18
16
 
19
- # @return [Logger] Logger with provided level and output.
20
- def self.create_simple_logger(level = Logger::FATAL, output = $stderr)
21
- # TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
22
- lambda do |severity, progname, message = nil, &block|
23
- return false if severity < level
24
-
25
- message = block ? block.call : message
26
- formatted_message = case message
27
- when String
28
- message
29
- when Exception
30
- format "%s (%s)\n%s",
31
- message.message, message.class, (message.backtrace || []).join("\n")
32
- else
33
- message.inspect
34
- end
35
-
36
- output.print format "[%s] %5s -- %s: %s\n",
37
- Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
38
- Logger::SEV_LABEL[severity],
39
- progname,
40
- formatted_message
41
- true
42
- end
43
- end
44
-
45
- # Use logger created by #create_simple_logger to log concurrent-ruby messages.
46
- def self.use_simple_logger(level = Logger::FATAL, output = $stderr)
47
- Concurrent.global_logger = create_simple_logger level, output
48
- end
49
-
50
- # @return [Logger] Logger with provided level and output.
51
- # @deprecated
52
- def self.create_stdlib_logger(level = Logger::FATAL, output = $stderr)
53
- logger = Logger.new(output)
54
- logger.level = level
55
- logger.formatter = lambda do |severity, datetime, progname, msg|
56
- formatted_message = case msg
57
- when String
58
- msg
59
- when Exception
60
- format "%s (%s)\n%s",
61
- msg.message, msg.class, (msg.backtrace || []).join("\n")
62
- else
63
- msg.inspect
64
- end
65
- format "[%s] %5s -- %s: %s\n",
66
- datetime.strftime('%Y-%m-%d %H:%M:%S.%L'),
67
- severity,
68
- progname,
69
- formatted_message
70
- end
71
-
72
- lambda do |loglevel, progname, message = nil, &block|
73
- logger.add loglevel, message, progname, &block
74
- end
75
- end
76
-
77
- # Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
78
- # @deprecated
79
- def self.use_stdlib_logger(level = Logger::FATAL, output = $stderr)
80
- Concurrent.global_logger = create_stdlib_logger level, output
81
- end
82
-
83
- # TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods
84
-
85
- # Suppresses all output when used for logging.
86
- NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
87
-
88
- # @!visibility private
89
- GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(Logger::WARN))
90
- private_constant :GLOBAL_LOGGER
91
-
92
- def self.global_logger
93
- GLOBAL_LOGGER.value
94
- end
95
-
96
- def self.global_logger=(value)
97
- GLOBAL_LOGGER.value = value
98
- end
99
-
100
17
  # @!visibility private
101
18
  GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor }
102
19
  private_constant :GLOBAL_FAST_EXECUTOR
@@ -136,14 +53,14 @@ module Concurrent
136
53
  #
137
54
  # @return [ThreadPoolExecutor] the thread pool
138
55
  def self.global_fast_executor
139
- GLOBAL_FAST_EXECUTOR.value
56
+ GLOBAL_FAST_EXECUTOR.value!
140
57
  end
141
58
 
142
59
  # Global thread pool optimized for long, blocking (IO) *tasks*.
143
60
  #
144
61
  # @return [ThreadPoolExecutor] the thread pool
145
62
  def self.global_io_executor
146
- GLOBAL_IO_EXECUTOR.value
63
+ GLOBAL_IO_EXECUTOR.value!
147
64
  end
148
65
 
149
66
  def self.global_immediate_executor
@@ -154,7 +71,7 @@ module Concurrent
154
71
  #
155
72
  # @return [Concurrent::TimerSet] the thread pool
156
73
  def self.global_timer_set
157
- GLOBAL_TIMER_SET.value
74
+ GLOBAL_TIMER_SET.value!
158
75
  end
159
76
 
160
77
  # General access point to global executors.
@@ -1,7 +1,7 @@
1
1
  require 'thread'
2
2
  require 'concurrent/concern/obligation'
3
3
  require 'concurrent/executor/immediate_executor'
4
- require 'concurrent/synchronization'
4
+ require 'concurrent/synchronization/lockable_object'
5
5
 
6
6
  module Concurrent
7
7
 
@@ -67,7 +67,7 @@ module Concurrent
67
67
 
68
68
  # Return the value this object represents after applying the options
69
69
  # specified by the `#set_deref_options` method. If the delayed operation
70
- # raised an exception this method will return nil. The execption object
70
+ # raised an exception this method will return nil. The exception object
71
71
  # can be accessed via the `#reason` method.
72
72
  #
73
73
  # @param [Numeric] timeout the maximum number of seconds to wait
@@ -66,4 +66,9 @@ module Concurrent
66
66
  end
67
67
  end
68
68
 
69
+ # @!macro internal_implementation_note
70
+ class ConcurrentUpdateError < ThreadError
71
+ # frozen pre-allocated backtrace to speed ConcurrentUpdateError
72
+ CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
73
+ end
69
74
  end
@@ -289,6 +289,7 @@ module Concurrent
289
289
  end
290
290
 
291
291
  if Concurrent.on_jruby?
292
+ require 'concurrent/utility/native_extension_loader'
292
293
 
293
294
  # @!macro internal_implementation_note
294
295
  # @!visibility private
@@ -1,7 +1,7 @@
1
1
  require 'concurrent/errors'
2
2
  require 'concurrent/concern/deprecation'
3
3
  require 'concurrent/executor/executor_service'
4
- require 'concurrent/synchronization'
4
+ require 'concurrent/synchronization/lockable_object'
5
5
 
6
6
  module Concurrent
7
7
 
@@ -39,6 +39,10 @@ module Concurrent
39
39
  # The number of tasks that have been completed by the pool since construction.
40
40
  # @return [Integer] The number of tasks that have been completed by the pool since construction.
41
41
 
42
+ # @!macro thread_pool_executor_method_active_count
43
+ # The number of threads that are actively executing tasks.
44
+ # @return [Integer] The number of threads that are actively executing tasks.
45
+
42
46
  # @!macro thread_pool_executor_attr_reader_idletime
43
47
  # The number of seconds that a thread may be idle before being reclaimed.
44
48
  # @return [Integer] The number of seconds that a thread may be idle before being reclaimed.
@@ -1,7 +1,7 @@
1
- if Concurrent.on_jruby?
1
+ require 'concurrent/utility/engine'
2
2
 
3
+ if Concurrent.on_jruby?
3
4
  require 'concurrent/errors'
4
- require 'concurrent/utility/engine'
5
5
  require 'concurrent/executor/abstract_executor_service'
6
6
 
7
7
  module Concurrent
@@ -57,15 +57,11 @@ if Concurrent.on_jruby?
57
57
  end
58
58
 
59
59
  def ns_shuttingdown?
60
- if @executor.respond_to? :isTerminating
61
- @executor.isTerminating
62
- else
63
- false
64
- end
60
+ @executor.isShutdown && !@executor.isTerminated
65
61
  end
66
62
 
67
63
  def ns_shutdown?
68
- @executor.isShutdown || @executor.isTerminated
64
+ @executor.isTerminated
69
65
  end
70
66
 
71
67
  class Job
@@ -88,10 +84,11 @@ if Concurrent.on_jruby?
88
84
 
89
85
  def initialize(daemonize = true)
90
86
  @daemonize = daemonize
87
+ @java_thread_factory = java.util.concurrent.Executors.defaultThreadFactory
91
88
  end
92
89
 
93
90
  def newThread(runnable)
94
- thread = java.util.concurrent.Executors.defaultThreadFactory().newThread(runnable)
91
+ thread = @java_thread_factory.newThread(runnable)
95
92
  thread.setDaemon(@daemonize)
96
93
  return thread
97
94
  end
@@ -73,6 +73,11 @@ if Concurrent.on_jruby?
73
73
  @executor.getCompletedTaskCount
74
74
  end
75
75
 
76
+ # @!macro thread_pool_executor_method_active_count
77
+ def active_count
78
+ @executor.getActiveCount
79
+ end
80
+
76
81
  # @!macro thread_pool_executor_attr_reader_idletime
77
82
  def idletime
78
83
  @executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS)
@@ -61,6 +61,13 @@ module Concurrent
61
61
  synchronize { @completed_task_count }
62
62
  end
63
63
 
64
+ # @!macro thread_pool_executor_method_active_count
65
+ def active_count
66
+ synchronize do
67
+ @pool.length - @ready.length
68
+ end
69
+ end
70
+
64
71
  # @!macro executor_service_method_can_overflow_question
65
72
  def can_overflow?
66
73
  synchronize { ns_limited_queue? }
@@ -1,4 +1,4 @@
1
- require 'concurrent/synchronization'
1
+ require 'concurrent/synchronization/lockable_object'
2
2
 
3
3
  module Concurrent
4
4
 
@@ -1,6 +1,6 @@
1
1
  require 'concurrent/errors'
2
2
  require 'concurrent/concern/logging'
3
- require 'concurrent/synchronization'
3
+ require 'concurrent/synchronization/lockable_object'
4
4
 
5
5
  module Concurrent
6
6
 
@@ -1,5 +1,8 @@
1
- require 'concurrent/atomics'
1
+ require 'concurrent/atomic/atomic_boolean'
2
+ require 'concurrent/atomic/atomic_fixnum'
3
+ require 'concurrent/atomic/event'
2
4
  require 'concurrent/executor/executor_service'
5
+ require 'concurrent/executor/ruby_executor_service'
3
6
 
4
7
  module Concurrent
5
8
 
@@ -3,7 +3,7 @@ require 'concurrent/atomic/event'
3
3
  require 'concurrent/collection/non_concurrent_priority_queue'
4
4
  require 'concurrent/executor/executor_service'
5
5
  require 'concurrent/executor/single_thread_executor'
6
-
6
+ require 'concurrent/errors'
7
7
  require 'concurrent/options'
8
8
 
9
9
  module Concurrent
@@ -162,7 +162,11 @@ module Concurrent
162
162
  # queue now must have the same pop time, or a closer one, as
163
163
  # when we peeked).
164
164
  task = synchronize { @queue.pop }
165
- task.executor.post { task.process_task }
165
+ begin
166
+ task.executor.post { task.process_task }
167
+ rescue RejectedExecutionError
168
+ # ignore and continue
169
+ end
166
170
  else
167
171
  @condition.wait([diff, 60].min)
168
172
  end
@@ -15,9 +15,11 @@ module Concurrent
15
15
  # @!macro internal_implementation_note
16
16
  HashImplementation = case
17
17
  when Concurrent.on_cruby?
18
- # Hash is thread-safe in practice because CRuby runs
19
- # threads one at a time and does not do context
20
- # switching during the execution of C functions.
18
+ # Hash is not fully thread-safe on CRuby, see
19
+ # https://bugs.ruby-lang.org/issues/19237
20
+ # https://github.com/ruby/ruby/commit/ffd52412ab
21
+ # https://github.com/ruby-concurrency/concurrent-ruby/issues/929
22
+ # So we will need to add synchronization here (similar to Concurrent::Map).
21
23
  ::Hash
22
24
 
23
25
  when Concurrent.on_jruby?
@@ -28,15 +30,6 @@ module Concurrent
28
30
  end
29
31
  JRubyHash
30
32
 
31
- when Concurrent.on_rbx?
32
- require 'monitor'
33
- require 'concurrent/thread_safe/util/data_structures'
34
-
35
- class RbxHash < ::Hash
36
- end
37
- ThreadSafe::Util.make_synchronized_on_rbx RbxHash
38
- RbxHash
39
-
40
33
  when Concurrent.on_truffleruby?
41
34
  require 'concurrent/thread_safe/util/data_structures'
42
35
 
@@ -1,5 +1,5 @@
1
1
  require 'concurrent/synchronization/abstract_struct'
2
- require 'concurrent/synchronization'
2
+ require 'concurrent/synchronization/lockable_object'
3
3
 
4
4
  module Concurrent
5
5
 
@@ -3,7 +3,8 @@ require 'concurrent/errors'
3
3
  require 'concurrent/collection/copy_on_write_observer_set'
4
4
  require 'concurrent/concern/obligation'
5
5
  require 'concurrent/concern/observable'
6
- require 'concurrent/synchronization'
6
+ require 'concurrent/executor/safe_task_executor'
7
+ require 'concurrent/synchronization/lockable_object'
7
8
 
8
9
  module Concurrent
9
10
 
@@ -1,6 +1,5 @@
1
1
  require 'thread'
2
2
  require 'concurrent/constants'
3
- require 'concurrent/synchronization'
4
3
  require 'concurrent/utility/engine'
5
4
 
6
5
  module Concurrent
@@ -10,17 +9,20 @@ module Concurrent
10
9
  # @!visibility private
11
10
  MapImplementation = case
12
11
  when Concurrent.on_jruby?
12
+ require 'concurrent/utility/native_extension_loader'
13
13
  # noinspection RubyResolve
14
14
  JRubyMapBackend
15
15
  when Concurrent.on_cruby?
16
16
  require 'concurrent/collection/map/mri_map_backend'
17
17
  MriMapBackend
18
- when Concurrent.on_truffleruby? && defined?(::TruffleRuby::ConcurrentMap)
19
- require 'concurrent/collection/map/truffleruby_map_backend'
20
- TruffleRubyMapBackend
21
- when Concurrent.on_truffleruby? || Concurrent.on_rbx?
22
- require 'concurrent/collection/map/atomic_reference_map_backend'
23
- AtomicReferenceMapBackend
18
+ when Concurrent.on_truffleruby?
19
+ if defined?(::TruffleRuby::ConcurrentMap)
20
+ require 'concurrent/collection/map/truffleruby_map_backend'
21
+ TruffleRubyMapBackend
22
+ else
23
+ require 'concurrent/collection/map/synchronized_map_backend'
24
+ SynchronizedMapBackend
25
+ end
24
26
  else
25
27
  warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation'
26
28
  require 'concurrent/collection/map/synchronized_map_backend'
@@ -44,6 +46,12 @@ module Concurrent
44
46
  # @note Atomic methods taking a block do not allow the `self` instance
45
47
  # to be used within the block. Doing so will cause a deadlock.
46
48
 
49
+ # @!method []=(key, value)
50
+ # Set a value with key
51
+ # @param [Object] key
52
+ # @param [Object] value
53
+ # @return [Object] the new value
54
+
47
55
  # @!method compute_if_absent(key)
48
56
  # Compute and store new value for key if the key is absent.
49
57
  # @param [Object] key
@@ -117,41 +125,38 @@ module Concurrent
117
125
  # @return [true, false] true if deleted
118
126
  # @!macro map.atomic_method
119
127
 
120
- #
121
- def initialize(options = nil, &block)
122
- if options.kind_of?(::Hash)
123
- validate_options_hash!(options)
124
- else
125
- options = nil
126
- end
128
+ # NonConcurrentMapBackend handles default_proc natively
129
+ unless defined?(Collection::NonConcurrentMapBackend) and self < Collection::NonConcurrentMapBackend
127
130
 
128
- super(options)
129
- @default_proc = block
130
- end
131
+ # @param [Hash, nil] options options to set the :initial_capacity or :load_factor. Ignored on some Rubies.
132
+ # @param [Proc] default_proc Optional block to compute the default value if the key is not set, like `Hash#default_proc`
133
+ def initialize(options = nil, &default_proc)
134
+ if options.kind_of?(::Hash)
135
+ validate_options_hash!(options)
136
+ else
137
+ options = nil
138
+ end
131
139
 
132
- # Get a value with key
133
- # @param [Object] key
134
- # @return [Object] the value
135
- def [](key)
136
- if value = super # non-falsy value is an existing mapping, return it right away
137
- value
138
- # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call
139
- # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value
140
- # would be returned)
141
- # note: nil == value check is not technically necessary
142
- elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL))
143
- @default_proc.call(self, key)
144
- else
145
- value
140
+ super(options)
141
+ @default_proc = default_proc
146
142
  end
147
- end
148
143
 
149
- # Set a value with key
150
- # @param [Object] key
151
- # @param [Object] value
152
- # @return [Object] the new value
153
- def []=(key, value)
154
- super
144
+ # Get a value with key
145
+ # @param [Object] key
146
+ # @return [Object] the value
147
+ def [](key)
148
+ if value = super # non-falsy value is an existing mapping, return it right away
149
+ value
150
+ # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call
151
+ # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value
152
+ # would be returned)
153
+ # note: nil == value check is not technically necessary
154
+ elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL))
155
+ @default_proc.call(self, key)
156
+ else
157
+ value
158
+ end
159
+ end
155
160
  end
156
161
 
157
162
  alias_method :get, :[]
@@ -197,7 +202,6 @@ module Concurrent
197
202
  # @yieldparam key [Object]
198
203
  # @yieldreturn [Object] default value
199
204
  # @return [Object] the value or default value
200
- # @!macro map.atomic_method_with_block
201
205
  def fetch_or_store(key, default_value = NULL)
202
206
  fetch(key) do
203
207
  put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value))
@@ -1,4 +1,4 @@
1
- require 'concurrent/synchronization'
1
+ require 'concurrent/synchronization/object'
2
2
 
3
3
  module Concurrent
4
4
 
@@ -1,5 +1,5 @@
1
1
  require 'concurrent/synchronization/abstract_struct'
2
- require 'concurrent/synchronization'
2
+ require 'concurrent/synchronization/lockable_object'
3
3
 
4
4
  module Concurrent
5
5
 
@@ -1,5 +1,5 @@
1
1
  require 'concurrent/concern/dereferenceable'
2
- require 'concurrent/synchronization'
2
+ require 'concurrent/synchronization/object'
3
3
 
4
4
  module Concurrent
5
5
 
@@ -66,7 +66,7 @@ module Concurrent
66
66
  # Start by requiring promises
67
67
  #
68
68
  # ```ruby
69
- # require 'concurrent'
69
+ # require 'concurrent/promise'
70
70
  # ```
71
71
  #
72
72
  # Then create one