Ractor.set_if_absent(key)

to initialize ractor local storage in thread-safety.
[Feature #20875]
This commit is contained in:
Koichi Sasada 2024-12-13 04:52:34 +09:00
parent 79d90e7351
commit 0bdb38ba6b
Notes: git 2024-12-12 21:22:32 +00:00
4 changed files with 70 additions and 0 deletions

View File

@ -1503,6 +1503,21 @@ assert_equal '[nil, "b", "a"]', %q{
ans << Ractor.current[:key]
}
assert_equal '1', %q{
N = 1_000
Ractor.new{
a = []
1_000.times.map{|i|
Thread.new(i){|i|
Thread.pass if i < N
a << Ractor.store_if_absent(:i){ i }
a << Ractor.current[:i]
}
}.each(&:join)
a.uniq.size
}.take
}
###
### Synchronization tests
###

View File

@ -3882,6 +3882,56 @@ ractor_local_value_set(rb_execution_context_t *ec, VALUE self, VALUE sym, VALUE
return val;
}
struct ractor_local_storage_store_data {
rb_execution_context_t *ec;
struct rb_id_table *tbl;
ID id;
VALUE sym;
};
static VALUE
ractor_local_value_store_i(VALUE ptr)
{
VALUE val;
struct ractor_local_storage_store_data *data = (struct ractor_local_storage_store_data *)ptr;
if (rb_id_table_lookup(data->tbl, data->id, &val)) {
// after synchronization, we found already registerred entry
}
else {
val = rb_yield(Qnil);
ractor_local_value_set(data->ec, Qnil, data->sym, val);
}
return val;
}
static VALUE
ractor_local_value_store_if_absent(rb_execution_context_t *ec, VALUE self, VALUE sym)
{
rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
struct ractor_local_storage_store_data data = {
.ec = ec,
.sym = sym,
.id = SYM2ID(rb_to_symbol(sym)),
.tbl = cr->idkey_local_storage,
};
VALUE val;
if (data.tbl == NULL) {
data.tbl = cr->idkey_local_storage = rb_id_table_create(2);
}
else if (rb_id_table_lookup(data.tbl, data.id, &val)) {
// already set
return val;
}
if (!cr->local_storage_store_lock) {
cr->local_storage_store_lock = rb_mutex_new();
}
return rb_mutex_synchronize(cr->local_storage_store_lock, ractor_local_value_store_i, (VALUE)&data);
}
// Ractor::Channel (emulate with Ractor)
typedef rb_ractor_t rb_ractor_channel_t;

View File

@ -856,6 +856,10 @@ class Ractor
Primitive.ractor_local_value_set(sym, val)
end
def self.store_if_absent(sym)
Primitive.ractor_local_value_store_if_absent(sym)
end
# returns main ractor
def self.main
__builtin_cexpr! %q{

View File

@ -180,6 +180,7 @@ struct rb_ractor_struct {
st_table *local_storage;
struct rb_id_table *idkey_local_storage;
VALUE local_storage_store_lock;
VALUE r_stdin;
VALUE r_stdout;