concurrent-ruby 0.8.0.pre2-java → 0.9.0-java

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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +114 -3
  3. data/README.md +111 -55
  4. data/lib/concurrent.rb +90 -14
  5. data/lib/concurrent/async.rb +143 -51
  6. data/lib/concurrent/atom.rb +131 -0
  7. data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
  8. data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
  9. data/lib/concurrent/atomic/atomic_reference.rb +49 -0
  10. data/lib/concurrent/atomic/condition.rb +23 -12
  11. data/lib/concurrent/atomic/count_down_latch.rb +23 -21
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
  13. data/lib/concurrent/atomic/event.rb +33 -42
  14. data/lib/concurrent/atomic/read_write_lock.rb +252 -0
  15. data/lib/concurrent/atomic/semaphore.rb +64 -89
  16. data/lib/concurrent/atomic/thread_local_var.rb +130 -58
  17. data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
  18. data/lib/concurrent/atomic_reference/direct_update.rb +34 -3
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +17 -39
  21. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
  22. data/lib/concurrent/atomic_reference/rbx.rb +4 -1
  23. data/lib/concurrent/atomic_reference/ruby.rb +6 -3
  24. data/lib/concurrent/atomics.rb +74 -4
  25. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
  26. data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
  27. data/lib/concurrent/collection/priority_queue.rb +300 -245
  28. data/lib/concurrent/concern/deprecation.rb +34 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +27 -0
  31. data/lib/concurrent/concern/obligation.rb +228 -0
  32. data/lib/concurrent/concern/observable.rb +85 -0
  33. data/lib/concurrent/configuration.rb +234 -109
  34. data/lib/concurrent/dataflow.rb +2 -3
  35. data/lib/concurrent/delay.rb +141 -50
  36. data/lib/concurrent/edge.rb +30 -0
  37. data/lib/concurrent/errors.rb +19 -7
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +51 -33
  40. data/lib/concurrent/executor/executor.rb +46 -299
  41. data/lib/concurrent/executor/executor_service.rb +521 -0
  42. data/lib/concurrent/executor/fixed_thread_pool.rb +196 -23
  43. data/lib/concurrent/executor/immediate_executor.rb +9 -9
  44. data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
  45. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  46. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  47. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  48. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  49. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  50. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  51. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  52. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  53. data/lib/concurrent/executor/thread_pool_executor.rb +73 -60
  54. data/lib/concurrent/executor/timer_set.rb +96 -84
  55. data/lib/concurrent/executors.rb +1 -1
  56. data/lib/concurrent/future.rb +71 -38
  57. data/lib/concurrent/immutable_struct.rb +89 -0
  58. data/lib/concurrent/ivar.rb +152 -60
  59. data/lib/concurrent/lazy_register.rb +40 -20
  60. data/lib/concurrent/maybe.rb +226 -0
  61. data/lib/concurrent/mutable_struct.rb +227 -0
  62. data/lib/concurrent/mvar.rb +44 -43
  63. data/lib/concurrent/promise.rb +229 -136
  64. data/lib/concurrent/scheduled_task.rb +341 -43
  65. data/lib/concurrent/settable_struct.rb +127 -0
  66. data/lib/concurrent/synchronization.rb +17 -0
  67. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  68. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  69. data/lib/concurrent/synchronization/condition.rb +53 -0
  70. data/lib/concurrent/synchronization/java_object.rb +34 -0
  71. data/lib/concurrent/synchronization/lock.rb +32 -0
  72. data/lib/concurrent/synchronization/monitor_object.rb +26 -0
  73. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  74. data/lib/concurrent/synchronization/object.rb +78 -0
  75. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  76. data/lib/concurrent/timer_task.rb +92 -103
  77. data/lib/concurrent/tvar.rb +42 -38
  78. data/lib/concurrent/utilities.rb +3 -1
  79. data/lib/concurrent/utility/at_exit.rb +97 -0
  80. data/lib/concurrent/utility/engine.rb +44 -0
  81. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  82. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  83. data/lib/concurrent/utility/processor_counter.rb +156 -0
  84. data/lib/concurrent/utility/timeout.rb +18 -14
  85. data/lib/concurrent/utility/timer.rb +11 -6
  86. data/lib/concurrent/version.rb +2 -1
  87. data/lib/concurrent_ruby.rb +1 -0
  88. data/lib/concurrent_ruby_ext.jar +0 -0
  89. metadata +46 -66
  90. data/lib/concurrent/actor.rb +0 -103
  91. data/lib/concurrent/actor/behaviour.rb +0 -70
  92. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  93. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  94. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  95. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  96. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  97. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  98. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  99. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  100. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  101. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  102. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  103. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  104. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  105. data/lib/concurrent/actor/context.rb +0 -154
  106. data/lib/concurrent/actor/core.rb +0 -217
  107. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  108. data/lib/concurrent/actor/envelope.rb +0 -41
  109. data/lib/concurrent/actor/errors.rb +0 -27
  110. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  111. data/lib/concurrent/actor/public_delegations.rb +0 -40
  112. data/lib/concurrent/actor/reference.rb +0 -81
  113. data/lib/concurrent/actor/root.rb +0 -37
  114. data/lib/concurrent/actor/type_check.rb +0 -48
  115. data/lib/concurrent/actor/utils.rb +0 -10
  116. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  117. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  118. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  119. data/lib/concurrent/actor/utils/pool.rb +0 -59
  120. data/lib/concurrent/actress.rb +0 -3
  121. data/lib/concurrent/agent.rb +0 -209
  122. data/lib/concurrent/atomic.rb +0 -92
  123. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  124. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  125. data/lib/concurrent/atomic/synchronization.rb +0 -51
  126. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  127. data/lib/concurrent/channel/channel.rb +0 -41
  128. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  129. data/lib/concurrent/channel/waitable_list.rb +0 -40
  130. data/lib/concurrent/channels.rb +0 -5
  131. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  132. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  133. data/lib/concurrent/collections.rb +0 -3
  134. data/lib/concurrent/dereferenceable.rb +0 -108
  135. data/lib/concurrent/executor/java_cached_thread_pool.rb +0 -32
  136. data/lib/concurrent/executor/java_fixed_thread_pool.rb +0 -31
  137. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +0 -29
  138. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +0 -32
  139. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  140. data/lib/concurrent/logging.rb +0 -20
  141. data/lib/concurrent/obligation.rb +0 -171
  142. data/lib/concurrent/observable.rb +0 -73
  143. data/lib/concurrent/options_parser.rb +0 -48
  144. data/lib/concurrent/utility/processor_count.rb +0 -152
  145. data/lib/extension_helper.rb +0 -37
@@ -0,0 +1,17 @@
1
+ require 'concurrent/utility/engine'
2
+ require 'concurrent/synchronization/abstract_object'
3
+ require 'concurrent/synchronization/java_object'
4
+ require 'concurrent/synchronization/mutex_object'
5
+ require 'concurrent/synchronization/monitor_object'
6
+ require 'concurrent/synchronization/rbx_object'
7
+ require 'concurrent/synchronization/object'
8
+
9
+ require 'concurrent/synchronization/condition'
10
+ require 'concurrent/synchronization/lock'
11
+
12
+ module Concurrent
13
+ # {include:file:doc/synchronization.md}
14
+ module Synchronization
15
+ end
16
+ end
17
+
@@ -0,0 +1,163 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!macro synchronization_object
5
+ # @!visibility private
6
+ class AbstractObject
7
+
8
+ # @!macro [attach] synchronization_object_method_initialize
9
+ #
10
+ # @abstract for helper ivar initialization if needed,
11
+ # otherwise it can be left empty. It has to call ns_initialize.
12
+ def initialize(*args, &block)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ protected
17
+
18
+ # @!macro [attach] synchronization_object_method_synchronize
19
+ #
20
+ # @yield runs the block synchronized against this object,
21
+ # equivalent of java's `synchronize(this) {}`
22
+ # @note can by made public in descendants if required by `public :synchronize`
23
+ def synchronize
24
+ raise NotImplementedError
25
+ end
26
+
27
+ # @!macro [attach] synchronization_object_method_ns_initialize
28
+ #
29
+ # initialization of the object called inside synchronize block
30
+ # @note has to be called manually when required in children of this class
31
+ # @example
32
+ # class Child < Concurrent::Synchornization::Object
33
+ # def initialize(*args, &block)
34
+ # super(&nil)
35
+ # synchronize { ns_initialize(*args, &block) }
36
+ # end
37
+ #
38
+ # def ns_initialize(*args, &block)
39
+ # @args = args
40
+ # end
41
+ # end
42
+ def ns_initialize(*args, &block)
43
+ end
44
+
45
+ # @!macro [attach] synchronization_object_method_ns_wait_until
46
+ #
47
+ # Wait until condition is met or timeout passes,
48
+ # protects against spurious wake-ups.
49
+ # @param [Numeric, nil] timeout in seconds, `nil` means no timeout
50
+ # @yield condition to be met
51
+ # @yieldreturn [true, false]
52
+ # @return [true, false] if condition met
53
+ # @note only to be used inside synchronized block
54
+ # @note to provide direct access to this method in a descendant add method
55
+ # ```
56
+ # def wait_until(timeout = nil, &condition)
57
+ # synchronize { ns_wait_until(timeout, &condition) }
58
+ # end
59
+ # ```
60
+ def ns_wait_until(timeout = nil, &condition)
61
+ if timeout
62
+ wait_until = Concurrent.monotonic_time + timeout
63
+ loop do
64
+ now = Concurrent.monotonic_time
65
+ condition_result = condition.call
66
+ # 0.001 correction to avoid error when `wait_until - now` is smaller than 0.0005 and rounded to 0
67
+ # when passed to java #wait(long timeout)
68
+ return condition_result if (now + 0.001) >= wait_until || condition_result
69
+ ns_wait wait_until - now
70
+ end
71
+ else
72
+ ns_wait timeout until condition.call
73
+ true
74
+ end
75
+ end
76
+
77
+ # @!macro [attach] synchronization_object_method_ns_wait
78
+ #
79
+ # Wait until another thread calls #signal or #broadcast,
80
+ # spurious wake-ups can happen.
81
+ #
82
+ # @param [Numeric, nil] timeout in seconds, `nil` means no timeout
83
+ # @return [self]
84
+ # @note only to be used inside synchronized block
85
+ # @note to provide direct access to this method in a descendant add method
86
+ # ```
87
+ # def wait(timeout = nil)
88
+ # synchronize { ns_wait(timeout) }
89
+ # end
90
+ # ```
91
+ def ns_wait(timeout = nil)
92
+ raise NotImplementedError
93
+ end
94
+
95
+ # @!macro [attach] synchronization_object_method_ns_signal
96
+ #
97
+ # Signal one waiting thread.
98
+ # @return [self]
99
+ # @note only to be used inside synchronized block
100
+ # @note to provide direct access to this method in a descendant add method
101
+ # ```
102
+ # def signal
103
+ # synchronize { ns_signal }
104
+ # end
105
+ # ```
106
+ def ns_signal
107
+ raise NotImplementedError
108
+ end
109
+
110
+ # @!macro [attach] synchronization_object_method_ns_broadcast
111
+ #
112
+ # Broadcast to all waiting threads.
113
+ # @return [self]
114
+ # @note only to be used inside synchronized block
115
+ # @note to provide direct access to this method in a descendant add method
116
+ # ```
117
+ # def broadcast
118
+ # synchronize { ns_broadcast }
119
+ # end
120
+ # ```
121
+ def ns_broadcast
122
+ raise NotImplementedError
123
+ end
124
+
125
+ # @!macro [attach] synchronization_object_method_ensure_ivar_visibility
126
+ #
127
+ # Allows to construct immutable objects where all fields are visible after initialization, not requiring
128
+ # further synchronization on access.
129
+ # @example
130
+ # class AClass
131
+ # attr_reader :val
132
+ # def initialize(val)
133
+ # @val = val # final value, after assignment it's not changed (just convention, not enforced)
134
+ # ensure_ivar_visibility!
135
+ # # now it can be shared as Java's final field
136
+ # end
137
+ # end
138
+ def ensure_ivar_visibility!
139
+ raise NotImplementedError
140
+ end
141
+
142
+ # @!macro [attach] synchronization_object_method_self_attr_volatile
143
+ #
144
+ # creates methods for reading and writing to a instance variable with volatile (Java semantic) instance variable
145
+ # return [Array<Symbol>] names of defined method names
146
+ def self.attr_volatile(*names)
147
+ names.each do |name|
148
+ ivar = :"@volatile_#{name}"
149
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
150
+ def #{name}
151
+ #{ivar}
152
+ end
153
+
154
+ def #{name}=(value)
155
+ #{ivar} = value
156
+ end
157
+ RUBY
158
+ end
159
+ names.map { |n| [n, :"#{n}="] }.flatten
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,158 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ # @!visibility private
5
+ # @!macro internal_implementation_note
6
+ module AbstractStruct
7
+
8
+ # @!visibility private
9
+ def initialize(*values)
10
+ super()
11
+ ns_initialize(*values)
12
+ ensure_ivar_visibility!
13
+ end
14
+
15
+ # @!macro [attach] struct_length
16
+ #
17
+ # Returns the number of struct members.
18
+ #
19
+ # @return [Fixnum] the number of struct members
20
+ def length
21
+ self.class::MEMBERS.length
22
+ end
23
+ alias_method :size, :length
24
+
25
+ # @!macro [attach] struct_members
26
+ #
27
+ # Returns the struct members as an array of symbols.
28
+ #
29
+ # @return [Array] the struct members as an array of symbols
30
+ def members
31
+ self.class::MEMBERS.dup
32
+ end
33
+
34
+ protected
35
+
36
+ # @!macro struct_values
37
+ #
38
+ # @!visibility private
39
+ def ns_values
40
+ @values.dup
41
+ end
42
+
43
+ # @!macro struct_values_at
44
+ #
45
+ # @!visibility private
46
+ def ns_values_at(indexes)
47
+ @values.values_at(*indexes)
48
+ end
49
+
50
+ # @!macro struct_to_h
51
+ #
52
+ # @!visibility private
53
+ def ns_to_h
54
+ length.times.reduce({}){|memo, i| memo[self.class::MEMBERS[i]] = @values[i]; memo}
55
+ end
56
+
57
+ # @!macro struct_get
58
+ #
59
+ # @!visibility private
60
+ def ns_get(member)
61
+ if member.is_a? Integer
62
+ if member >= @values.length
63
+ raise IndexError.new("offset #{member} too large for struct(size:#{@values.length})")
64
+ end
65
+ @values[member]
66
+ else
67
+ send(member)
68
+ end
69
+ rescue NoMethodError
70
+ raise NameError.new("no member '#{member}' in struct")
71
+ end
72
+
73
+ # @!macro struct_equality
74
+ #
75
+ # @!visibility private
76
+ def ns_equality(other)
77
+ self.class == other.class && self.values == other.values
78
+ end
79
+
80
+ # @!macro struct_each
81
+ #
82
+ # @!visibility private
83
+ def ns_each
84
+ values.each{|value| yield value }
85
+ end
86
+
87
+ # @!macro struct_each_pair
88
+ #
89
+ # @!visibility private
90
+ def ns_each_pair
91
+ @values.length.times do |index|
92
+ yield self.class::MEMBERS[index], @values[index]
93
+ end
94
+ end
95
+
96
+ # @!macro struct_select
97
+ #
98
+ # @!visibility private
99
+ def ns_select
100
+ values.select{|value| yield value }
101
+ end
102
+
103
+ # @!macro struct_inspect
104
+ #
105
+ # @!visibility private
106
+ def ns_inspect
107
+ struct = pr_underscore(self.class.ancestors[1])
108
+ clazz = ((self.class.to_s =~ /^#<Class:/) == 0) ? '' : " #{self.class}"
109
+ "#<#{struct}#{clazz} #{ns_to_h}>"
110
+ end
111
+
112
+ # @!macro struct_merge
113
+ #
114
+ # @!visibility private
115
+ def ns_merge(other, &block)
116
+ self.class.new(*self.to_h.merge(other, &block).values)
117
+ end
118
+
119
+ # @!visibility private
120
+ def pr_underscore(clazz)
121
+ word = clazz.to_s
122
+ word.gsub!(/::/, '/')
123
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
124
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
125
+ word.tr!("-", "_")
126
+ word.downcase!
127
+ word
128
+ end
129
+
130
+ # @!visibility private
131
+ def self.define_struct_class(parent, base, name, members, &block)
132
+ clazz = Class.new(base || Object) do
133
+ include parent
134
+ self.const_set(:MEMBERS, members.collect{|member| member.to_s.to_sym}.freeze)
135
+ def ns_initialize(*values)
136
+ raise ArgumentError.new('struct size differs') if values.length > length
137
+ @values = values.fill(nil, values.length..length-1)
138
+ end
139
+ end
140
+ unless name.nil?
141
+ begin
142
+ parent.const_set(name, clazz)
143
+ parent.const_get(name)
144
+ rescue NameError
145
+ raise NameError.new("identifier #{name} needs to be constant")
146
+ end
147
+ end
148
+ members.each_with_index do |member, index|
149
+ clazz.send(:define_method, member) do
150
+ @values[index]
151
+ end
152
+ end
153
+ clazz.class_exec(&block) unless block.nil?
154
+ clazz
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,53 @@
1
+ module Concurrent
2
+ module Synchronization
3
+ class Condition < Object
4
+
5
+ singleton_class.send :alias_method, :private_new, :new
6
+ private_class_method :new
7
+
8
+ def initialize(lock)
9
+ @Lock = lock
10
+ ensure_ivar_visibility!
11
+ super()
12
+ end
13
+
14
+ def wait(timeout = nil)
15
+ @Lock.synchronize { ns_wait(timeout) }
16
+ end
17
+
18
+ def ns_wait(timeout = nil)
19
+ synchronize { super(timeout) }
20
+ end
21
+
22
+ def wait_until(timeout = nil, &condition)
23
+ @Lock.synchronize { ns_wait_until(timeout, &condition) }
24
+ end
25
+
26
+ def ns_wait_until(timeout = nil, &condition)
27
+ synchronize { super(timeout, &condition) }
28
+ end
29
+
30
+ def signal
31
+ @Lock.synchronize { ns_signal }
32
+ end
33
+
34
+ def ns_signal
35
+ synchronize { super }
36
+ end
37
+
38
+ def broadcast
39
+ @Lock.synchronize { ns_broadcast }
40
+ end
41
+
42
+ def ns_broadcast
43
+ synchronize { super }
44
+ end
45
+ end
46
+
47
+ class Object < Implementation
48
+ def new_condition
49
+ Condition.private_new(self)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,34 @@
1
+ require 'concurrent/utility/native_extension_loader' # load native part first
2
+
3
+ module Concurrent
4
+ module Synchronization
5
+
6
+ if Concurrent.on_jruby?
7
+
8
+ # @!visibility private
9
+ # @!macro internal_implementation_note
10
+ class JavaObject < AbstractObject
11
+
12
+ def self.attr_volatile(*names)
13
+ names.each do |name|
14
+
15
+ ivar = :"@volatile_#{name}"
16
+
17
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
18
+ def #{name}
19
+ instance_variable_get_volatile(:#{ivar})
20
+ end
21
+
22
+ def #{name}=(value)
23
+ instance_variable_set_volatile(:#{ivar}, value)
24
+ end
25
+ RUBY
26
+
27
+ end
28
+ names.map { |n| [n, :"#{n}="] }.flatten
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ module Concurrent
2
+ module Synchronization
3
+ class Lock < Object
4
+
5
+ public :synchronize
6
+
7
+ def wait(timeout = nil)
8
+ synchronize { ns_wait(timeout) }
9
+ end
10
+
11
+ public :ns_wait
12
+
13
+ def wait_until(timeout = nil, &condition)
14
+ synchronize { ns_wait_until(timeout, &condition) }
15
+ end
16
+
17
+ public :ns_wait_until
18
+
19
+ def signal
20
+ synchronize { ns_signal }
21
+ end
22
+
23
+ public :ns_signal
24
+
25
+ def broadcast
26
+ synchronize { ns_broadcast }
27
+ end
28
+
29
+ public :ns_broadcast
30
+ end
31
+ end
32
+ end