Skip to content

Commit

Permalink
Merge pull request #666 from haridutt12/master
Browse files Browse the repository at this point in the history
thread safe set implementation
  • Loading branch information
pitr-ch committed Feb 24, 2018
2 parents da5c4a9 + cef13b9 commit 50ed4a5
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -67,6 +67,7 @@ Collection classes that were originally part of the (deprecated) `thread_safe` g

* [Array](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Array.html) A thread-safe subclass of Ruby's standard [Array](http://ruby-doc.org/core-2.2.0/Array.html).
* [Hash](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Hash.html) A thread-safe subclass of Ruby's standard [Hash](http://ruby-doc.org/core-2.2.0/Hash.html).
* [Set](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Set.html) A thread-safe subclass of Ruby's standard [Set](http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html).
* [Map](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Map.html) A hash-like object that should have much better performance characteristics, especially under high concurrency, than `Concurrent::Hash`.
* [Tuple](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Tuple.html) A fixed size array with volatile (synchronized, thread safe) getters/setters.

Expand Down
4 changes: 2 additions & 2 deletions lib/concurrent.rb
Expand Up @@ -12,6 +12,7 @@
require 'concurrent/atom'
require 'concurrent/array'
require 'concurrent/hash'
require 'concurrent/set'
require 'concurrent/map'
require 'concurrent/tuple'
require 'concurrent/async'
Expand Down Expand Up @@ -126,5 +127,4 @@
# * Exclude features that don't make sense in Ruby
# * Be small, lean, and loosely coupled
module Concurrent

end
end
47 changes: 47 additions & 0 deletions lib/concurrent/set.rb
@@ -0,0 +1,47 @@
require 'concurrent/utility/engine'
require 'concurrent/thread_safe/util'
require 'set'

module Concurrent
if Concurrent.on_cruby?

# Because MRI never runs code in parallel, the existing
# non-thread-safe structures should usually work fine.

# @!macro [attach] concurrent_Set
#
# A thread-safe subclass of Set. This version locks against the object
# itself for every method call, ensuring only one thread can be reading
# or writing at a time. This includes iteration methods like `#each`.
#
# @note `a += b` is **not** a **thread-safe** operation on
# `Concurrent::Set`. It reads Set `a`, then it creates new `Concurrent::Set`
# which is union of `a` and `b`, then it writes the union to `a`.
# The read and write are independent operations they do not form a single atomic
# operation therefore when two `+=` operations are executed concurrently updates
# may be lost. Use `#merge` instead.
#
# @see http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html Ruby standard library `Set`
class Set < ::Set;
end

elsif Concurrent.on_jruby?
require 'jruby/synchronized'

# @!macro concurrent_Set
class Set < ::Set
include JRuby::Synchronized
end

elsif Concurrent.on_rbx? || Concurrent.on_truffle?
require 'monitor'
require 'concurrent/thread_safe/util/array_hash_rbx'

# @!macro concurrent_Set
class Set < ::Set
end

ThreadSafe::Util.make_synchronized_on_rbx Set
end
end

1 change: 1 addition & 0 deletions spec/concurrent/array_spec.rb
Expand Up @@ -13,6 +13,7 @@ module Concurrent
end
end
end.map(&:join)
expect(ary).to be_empty
end

describe '#slice' do
Expand Down
2 changes: 1 addition & 1 deletion spec/concurrent/channel_spec.rb
Expand Up @@ -611,7 +611,7 @@ module Concurrent
latch.wait(10)
expect(actual).to eq expected
end
end
end

context '.go_loop_via' do

Expand Down
5 changes: 3 additions & 2 deletions spec/concurrent/hash_spec.rb
Expand Up @@ -7,11 +7,12 @@ module Concurrent
Thread.new do
1000.times do |j|
hsh[i * 1000 + j] = i
hsh[i * 1000 + j]
hsh.delete(i * 1000 + j)
expect(hsh[i * 1000 + j]).to eq(i)
expect(hsh.delete(i * 1000 + j)).to eq(i)
end
end
end.map(&:join)
expect(hsh).to be_empty
end
end
end
20 changes: 20 additions & 0 deletions spec/concurrent/set_spec.rb
@@ -0,0 +1,20 @@
require 'set'
module Concurrent
RSpec.describe Set do
let!(:set) { described_class.new }

it 'concurrency' do
(1..THREADS).map do |i|
Thread.new do
1000.times do
v = i
set << v
expect(set).not_to be_empty
set.delete(v)
end
end
end.map(&:join)
expect(set).to be_empty
end
end
end

0 comments on commit 50ed4a5

Please sign in to comment.