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]
|
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
|
### 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;
|
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)
|
// Ractor::Channel (emulate with Ractor)
|
||||||
|
|
||||||
typedef rb_ractor_t rb_ractor_channel_t;
|
typedef rb_ractor_t rb_ractor_channel_t;
|
||||||
|
@ -856,6 +856,10 @@ class Ractor
|
|||||||
Primitive.ractor_local_value_set(sym, val)
|
Primitive.ractor_local_value_set(sym, val)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.store_if_absent(sym)
|
||||||
|
Primitive.ractor_local_value_store_if_absent(sym)
|
||||||
|
end
|
||||||
|
|
||||||
# returns main ractor
|
# returns main ractor
|
||||||
def self.main
|
def self.main
|
||||||
__builtin_cexpr! %q{
|
__builtin_cexpr! %q{
|
||||||
|
@ -180,6 +180,7 @@ struct rb_ractor_struct {
|
|||||||
|
|
||||||
st_table *local_storage;
|
st_table *local_storage;
|
||||||
struct rb_id_table *idkey_local_storage;
|
struct rb_id_table *idkey_local_storage;
|
||||||
|
VALUE local_storage_store_lock;
|
||||||
|
|
||||||
VALUE r_stdin;
|
VALUE r_stdin;
|
||||||
VALUE r_stdout;
|
VALUE r_stdout;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user