Skip to content

Concurrent::Set is not thread-safe in CRuby #796

@fxn

Description

@fxn

Concurrent::Set returns Set in CRuby with this argument:

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

As discussed in #793, that is not enough for thread-safety, you also need the interface to be atomic somehow. For Hash and Array this holds because they are written in C, but Set is partially written in Ruby.

To demonstrate Concurrent::Set is not thread-safe I have created this artificial example:

require "concurrent-ruby"

class MySet < Concurrent::Set
  # Note include? is written in Ruby in Set, like delete?
  def include?(o)
    puts "include? call issued, 1 belongs to self, but there is a context switch"
    sleep 2
    super
  end
end

set = MySet[1]

t = Thread.new do
  sleep 1
  puts "clearing the set in a different thread"
  set.clear
end

p set.delete?(1) # should be self, but it is nil

t.join

By the time delete? is invoked, the set has the element 1, therefore, that method should return self (the set). However, it returns nil because clear was called during a context switch in the middle of the method execution.

Metadata

Metadata

Assignees

Labels

bugA bug in the library or documentation.high-priorityShould be done ASAP.looking-for-contributorWe are looking for a contributor to help with this issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions