Why *const T, *mut T : !Send + !Sync by default

while &T, &mut T is not?
and why Mutex: Sync needs T: Send?

Why *const T, *mut T : !Send + !Sync by default

Raw pointers are usually used for interacting with FFI, unsafe code, and sometimes that even implies interior mutability. Therefore, you actively need to consider whether a type containing a raw pointer is actually thread-safe. So, as a cautionary measure, raw pointers aren't Send or Sync, because marking them as such would be a thread safety footgun. If you specifically write your FFI-facing code in such a way that it is impossible to cause a race condition with them, then you can go ahead and manually, and unsafely, implement Send and/or Sync for your own types containing raw pointers. However, doing that automatically would be a footgun.

Since Mutex::lock() provides a mutable reference but only takes Self as an immutable reference, it is possible to acquire ownership of the inner value given only an immutable reference to a Mutex. Example:

let mutex = Mutex::new(Some(String::from("lol")));
let mut guard = mutex.lock().unwrap();
let inner = guard.take().unwrap();

Now, if the guard does this by-value stealing on a different thread than the one the Mutex and its inner value was created on, then the inner value ends up being moved to a different thread. Thus, it is necessary that T: Send if you want to have even immutable references to the Mutex in many threads.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.