Which container are thread-safe and can return mutable reference?

Hello!
This is my Iron handler type

pub struct PrepareArchiveHandler {
    client: memcache::Client,
}

But memcache client need to be mutable and thread-safe. It's implement Sync but how can I make it mutable? Cell container is not thread-safe. Arc can't produce mutable references if it isn't mutable itself.
Which container should I use in this case?

Mutex or RwLock

Do you mean I should like "implement" Sync for Cell myself?

I mean you should use Mutex or RwLock as container for Client.

This code are built.

pub struct PrepareArchiveHandler {
    requester: Requester,
    client: Mutex<Cell<Client>>,
}

fn handle(&self, req: &mut Request) -> IronResult<Response> {
    ...
    self.client.lock().unwrap().get_mut().add(....);
    ...
}
...

...

Do you mean I should like "implement" Sync for Cell myself?

But trouble isn't in thread-safe but in mutability!
I wrote code above but is there are more simple option?

You should not nest Cell inside Mutex. Mutex already allow you to mutate it.

You should not nest Cell inside Mutex. Mutex already allow you to mutate it.

Yes but Mutex::get_mut need a mutable mutex itself!

That's why you should lock it, not just try to get something.

2 Likes

Keep in mind that &mut in Rust is somewhat misleading. It's not required for mutation. It means exclusive access.

So your question is a bit self-contradictory. Because depending how you look at it, either all containers can return &mut in a thread-safe manner, or such thing can't possibly exist.

You can get exclusive &mut if you wrap a container in a Mutex, or anything else that guarantees exclusive access. But if it's exclusive access, then it's always exclusive to one thread by definition.

OTOH there many ways in Rust to mutate data behind shared references. But these aren't exclusive &mut ones, but shared & references (e.g. AtomicUsize and such).

So you can either use regular containers and locks (which are the "thread-safe containers"), or find containers do some clever lock-free access.

1 Like

Thanks!
This works to

pub struct PrepareArchiveHandler {
    client: Mutex<Client>,
}
...
self.client.lock().unwrap().deref_mut().add(...)
...

Explicit deref_mut should not be necessary. The compiler will automatically do it for you.

1 Like

I don't understand - &mut is always exclusive in rust. What do you mean exclusive &mut?

Thanks! I did'n know it.

It means that at any given time, only 1 &mut can be actively held within a closure in memory. Why? Well, if you have two &mut's, then how do you know that the two writers wont both edit the data at the same time? Such a concept is known as a data race. By forcing, at most, one &mut at compile-time, the compiler helps you program safely. It makes coding harder to do at first, but without this way of thinking, it leads to design errors that can cost quite literally billions of dollars (insofar). You can think of this mechanism as a compile-time RwLock (read/write lock)

I now this concept )
I don't understand what @kornel mean by "exclusive &mut".

I did not mean any other kind of &mut, just that &mut is always exclusive, and therefore can never be shared by threads.

Thanks to all!

If you want to learn more about the details of why &mut means exclusive, read this blog post

https://limpet.net/mbrubeck/2019/02/07/rust-a-unique-perspective.html

2 Likes

One of the "drawbacks" of Rust using &mut instead of &unique (e.g., for it to be more beginner-friendly) is that many Rustaceans end up thinking that a mutable reference is necessarily a &mut, which it is not: you can mutate something through a &_ (e.g., a &self) provided that thing has "Interior Mutability" / aliased mutability. For a very in-detail reasoning and comparison between exclusive-access (&mut) and shared / aliased mutability, you can have a look at this blog post (of mine): Mutation - part 2: To mut or not to mut ยท Another one bytes the Rust!

Many other languages have mutable references, but none have &mut references: that's unique to Rust.

3 Likes