I was recently confused by a compiler error while writing a multi-threaded program in Rust.
In short, I have a structure with an internal
Rc value, as follows.
Rc is not thread-safe, so it is protected by a lock and passed between threads with
Arc, so the following code is written.
However, the compiler’s throws an exception.
A does not implement
Send, but this makes people confused, I add locks so that things that are not thread-safe can be shared between threads, but why do I need to implement
Reconceptualizing Sync and Send
Send are very important foundational concepts in Rust multithreading.
Syncmeans that sharing between threads is safe.
Sendmeans that passing to another thread is safe.
Sync indicates that different threads can use the same object at the same time, for example, by reading the same constant at the same time. For a lock
Sync trait is satisfied because several threads can execute
lock() on the same lock at the same time, except that the internal mechanism of the lock will only allow only one thread to obtain the lock at the same time, but this does not matter, its external performance is satisfied. So for variables, a layer of
Mutex is usually sufficient to allow them to be shared between threads.
Send means that ownership can be passed between threads, and different threads can use the same object at different times. Thread A can create an object and then pass (send) it to thread B. Because of the ownership mechanism, thread B can then use the object and A cannot because ownership has been passed to B. However, if the object implements
Clone, then a copy can be made to another thread. The
Mutex does not implement the
Clone trait, so it is common to use
Arc<Mutex> to allow multiple threads to have the same lock at the same time.
It is worth mentioning that
Syncare flagged traits, meaning that they do not require any method implementation, and whether a structure satisfies them is manually flagged, not determined by the compiler, except for the condition that all members satisfy the trait, which is inferred from the fact that the structure also satisfies the trait. unsafe code, which cannot be protected by the compiler at implementation time and needs to be implemented carefully to ensure safety.
So it is easy to see that since it is safe to use at the same time (
Sync), it must also be safe to use at different times (
Send), after all, it cannot be passed to other threads, so how can several threads use it at the same time? So almost no object will be satisfied with
Sync and not
Back to the question
Let’s take a look at the definition in
You can see that
Mutex<T> can indeed add a
Sync trait to all types of
T, but only if
Send. Why? Because
Mutex must satisfy the
Send trait if it wants to implement
Sync, and then it also passes ownership of
T needs to satisfy
Send as well.
The fundamental problem is that
Rc doesn’t satisfy
Mutex can’t implement
Send, which then creates a series of unsatisfiable problems that eventually lead to the failure to pass between threads.
Send means that it is safe to pass between threads, but for
Rc, if I have multiple copies of
Rc in the current thread and pass one to another thread, then multiple threads own the object, but the reference counting operation in
Rc is not thread-safe, so
Rc does not satisfy
Send, which means that
Rc can only be passed to one thread during its entire can only be owned by one thread for its entire life cycle.
So why doesn’t
Rc work even if it is locked with
Mutex<Rc> so that multiple threads can’t operate on it at the same time? The ostensible reason is that
T to implement
Send. To take this a step further, imagine that you can make a copy of
Rc after obtaining the lock, and then take this copy out of the lock’s scope, so that several threads can modify the reference count at the same time, and the lock you’re envisioning is null and void, and Rust successfully saves you from that.
Hmm? You said
Mutex<Arc>would also have this problem? The
Arccopy is thread-safe and doesn’t cause problems.
What? You’re saying you can make a copy and have multiple threads modify it at the same time? A copy of
Arcis brought out from the lock, but
Arcdoesn’t give you a mut ref, and there is no way to modify it. Really want to modify it? Put a
The fundamental problem is that
Rc is not safe to pass between threads, so you can just replace it with