Ractor.set_if_absent(key)
to initialize ractor local storage in thread-safety. [Feature #20875]
This commit is contained in:
parent
79d90e7351
commit
0bdb38ba6b
Notes:
git
2024-12-12 21:22:32 +00:00
@ -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
|
||||
###
|
||||
|
50
ractor.c
50
ractor.c
@ -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;
|
||||
|
@ -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{
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user