On benign races on non-atomic locations

Let’s say I have a non-atomic reference that is set at the beginning of my main program or during the module initialisation and never set again.

I was wondering whether a domain spawn after that initial update could end up seeing the previous value.

I guess the answer lies in that sentence:

For non-atomic reads, the domains may read an arbitrary element of the history for that location, as long as it is not older than the timestamp in the domains’s frontier.

But unless I missed something the operational model described here does not talk about the state of the frontier at domain spawn creation time. Do they get the frontier of their spawning parent ? If that is the case then I guess then domains can only see the “right” value ?

Also let’s say that for extra safety or for not tripping out these thread sanitizers tools or code readers, I do use an atomic. Is there a large performance difference between a read on a atomic and a non-atomic ?

I’m thinking for example when the location is used as an indirection for a backend module:

module type API = sig val f : int -> int -> int end
let backend = ref (module (struct let f = ( + ) end) : API)
let f x y = let module Api = (val !backend) in Api.f x y

P.S. I just released Logs 0.9.0 which atomifies the various global references it holds

3 Likes

There shouldn’t be any issue with multiple readers reading a value that is only written to once, with a large enough delta between write and read. And this is definitely a large enough delta.

AFAIK atomic reads in this particular case (no contention) have minimal to no cost, depending on the architecture.

Yes, spawned domains inherit their frontier from their parent. At the implementation level, this is enforced by a number of C atomic accesses of the seq_cst kind in caml_domain_spawn.

3 Likes