A static global C string (as in this answer) doesn't have the Sync
trait.
pub static MY_STRING: &'static *const u8
= "hello" as const *u8;
// TODO: Simple assertion showing it's not Sync ;)
Sync
is described as
The precise definition is: a type
T
isSync
if&T
is thread-safe. In other words, there is no possibility of data races when passing&T
references between threads.
It seems like this is entirely readonly and has static lifetime, so why isn't it safe to pass a reference?
The chapter Send and Sync in The Rustonomicon describes what it means for a type to be
Send
orSync
. It mentions that:But that just begs the question; why doesn't
*const T
implementSync
? Why do the safety guards matter?Just before that, it says:
This is the key reason why raw pointers are neither
Send
norSync
. If you defined a struct that encapsulates a raw pointer, but only expose it as a&T
or&mut T
in the struct's API, did you really make sure that your struct respects the contracts ofSend
andSync
? If raw pointers wereSend
, thenRc<T>
would also beSend
by default, so it would have to explicitly opt-out. (In the source, there is in fact an explicit opt-out forRc<T>
, but it's only for documentation purposes, because it's actually redundant.)OK, let's recap: they're unsafe to implement, but they're automatically derived. Isn't that a weird combination? Actually, it's not as bad as it sounds. Most primitive types, like
u32
, areSend
andSync
. Simply compounding primitive values into a struct or enum is not enough to disqualify the type forSend
orSync
. Therefore, you need a struct or enum with non-Send
or non-Sync
before you need to write anunsafe impl
.Send
andSync
are marker traits, which means they have no methods. Therefore, when a function or type puts aSend
orSync
bound on a type parameter, it's relying on the type to respect a particular contract across all of its API. Because of this: