Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are examples of types that implement only one of Send and Sync?

Tags:

rust

People also ask

What is the Send trait?

Send means that a type is safe to move from one thread to another. If the same type also implements Copy , this also means that it is safe to copy from one thread to another. Sync means that a type is safe to reference from multiple threads at the same time.

What is send sync in Rust?

Rust captures this through the Send and Sync traits. A type is Send if it is safe to send it to another thread. A type is Sync if it is safe to share between threads (T is Sync if and only if &T is Send).

What are rust traits?

A trait in Rust is a group of methods that are defined for a particular type. Traits are an abstract definition of shared behavior amongst different types. So, in a way, traits are to Rust what interfaces are to Java or abstract classes are to C++. A trait method is able to access other methods within that trait.

Why is RC not send?

If you need mutability, put a Cell or RefCell inside the Rc ; see an example of mutability inside an Rc . Rc uses non-atomic reference counting. This means that overhead is very low, but an Rc cannot be sent between threads, and consequently Rc does not implement Send .


First of all, it is important to realize that most structs (or enums) are Send:

  • any struct that does not contain any reference can be Send + 'static
  • any struct that contain references with a lower-bound lifetime of 'a can be Send + 'a

As a result, you would generally expect any Sync struct to be Send too, because Send is such an easy bar to reach (compared to the much harder bar of being Sync which requires safe concurrent modification from multiple threads).


However, nothing prevents the creator of a type to specifically mark it as not Send. For example, let's resuscitate conditions!

The idea of conditions, in Lisp, is that you setup a handler for a given condition (say: FileNotFound) and then when deep in the stack this condition is met then your handler is called.

How would you implement this in Rust?

Well, to preserve threads independence, you would use thread-local storage for the condition handlers (see std::thread_local!). Each condition would be a stack of condition handlers, with either only the top one invoked or an iterative process starting from the top one but reaching down until one succeeds.

But then, how would you set them?

Personally, I'd use RAII! I would bind the condition handler in the thread-local stack and register it in the frame (for example, using an intrusive doubly-linked list as the stack).

This way, when I am done, the condition handler automatically un-registers itself.

Of course, the system has to account for users doing unexpected things (like storing the condition handlers in the heap and not dropping them in the order they were created), and this is why we use a doubly-linked list, so that the handler can un-register itself from the middle of the stack if necessary.

So we have a:

struct ConditionHandler<T> {
    handler: T,
    prev: Option<*mut ConditionHandler<T>>,
    next: Option<*mut ConditionHandler<T>>,
}

and the "real" handler is passed by the user as T.


Would this handler be Sync?

Possibly, depends how you create it but there is no reason you could not create a handler so that a reference to it could not be shared between multiple threads.

Note: those threads could not access its prev/next data members, which are private, and need not be Sync.

Would this handler be Send?

Unless specific care is taken, no.

The prev and next fields are not protected against concurrent accesses, and even worse if the handler were to be dropped while another thread had obtained a reference to it (for example, another handler trying to un-register itself) then this now dangling reference would cause Undefined Behavior.

Note: the latter issue means that just switching Option<*mut Handler<T>> for AtomicPtr<ConditionHandler<T>> is not sufficient; see Common Pitfalls in Writing Lock-Free Algorithms for more details.


And there you have it: a ConditionHandler<T> is Sync if T is Sync but will never be Send (as is).

For completeness, many types implement Send but not Sync (most Send types, actually): Option or Vec for example.


Cell and RefCell implement Send but not Sync because they can be safely sent between threads but not shared between them.