Rust Lifetimes with mpsc::Sender<T<'a>> and threads - multithreading

I'm creating a multi-threaded application where I create a receiving channel and a structure to hold the sending channel (to be used later by the implementation). However, the type I'm sending through the channel has a lifetime specification. This type is websocket::message:Message
from the rusts-weboscket library. Because of this specification, rust can't seem to correctly infer lifetimes when it gets passed through a thread.
Here's a rust playground example of this error:
https://play.rust-lang.org/?gist=7e37547d1c811185654f10a6a461e1ef&version=stable&backtrace=1
Now, I have tried using crossbeam to scope the lifetime, and this seems to solve that immediate issue, but in practically just delegates the lifetime specification issue somewhere else.
In my code I get the error:
$ cargo check
Compiling rump v0.1.0 (file:///home/alainh/UPenn/CIS198/Rump)
transport.rs:200:42: 200:57 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements [E0495]
transport.rs:200 self.sender.send(self.serializer.encode(message));
^~~~~~~~~~~~~~~
transport.rs:199:5: 202:6 help: consider using an explicit lifetime parameter as shown: fn send<T: Encodable>(&'a mut self, message: &T) -> WampResult<()>
transport.rs:199 fn send<T: Encodable>(&mut self, message: &T) -> WampResult<()> {
transport.rs:200 self.sender.send(self.serializer.encode(message));
transport.rs:201 Ok(())
transport.rs:202 }
error: aborting due to previous error
Could not compile `rump`.
The line in question is this one:
https://github.com/aehernandez/Rump/blob/ad717c7ef11857e94d0e1c02539667c8034676c4/src/transport.rs#L199
At this point I'm unsure how to exactly solve this lifetime issue. I don't want to keep delegating it somewhere else. Is there a good solution to this?

When you spawn a thread it can potentially live forever; certainly outliving your Transport<'a> type for any lifetime 'a other than 'static (the error messages are very confusing though). When you call thread::spawn with a closure, that closure must have the 'static lifetime, which is only true if 'a == 'static.
As you are not actually sending an object with a lifetime across the channel, consider using the 'static lifetime explicitly:
impl Connector for Transport<'static> {
...
}
Playpen
Edit:
Manually annotating the types for the sender and receiver
let (tx, rx): (mpsc::Sender<Message<'a>>, mpsc::Receiver<Message<'a>>) = mpsc::channel();
let tx_send: mpsc::Sender<Message<'a>> = tx.clone();
shows you a much more sensible error
<anon>:27:22: 27:35 error: the type `[closure#<anon>:27:36: 29:10 tx_send:std::sync::mpsc::Sender<Message<'a>>]` does not fulfill the required lifetime [E0477]
<anon>:27 let handle = thread::spawn(move || {
^~~~~~~~~~~~~
note: type must outlive the static lifetime
error: aborting due to previous error
playpen: application terminated with error code 101
Playpen

Related

How to understand "primitive types are Sync" in rust?

I am reading https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html
It says
In other words, any type T is Sync if &T (an immutable reference to T) is Send, meaning the reference can be sent safely to another thread. Similar to Send, primitive types are Sync
How to understand this? If primitive types are Sync, so integer such as i32 is Sync. Thus &i32 can be sent safely to another thread. But I don't think so. I don't think a number reference in main thread can be send to another thread.
You're confusing the concept of thread-safety with the concept of lifetime.
You are correct in that a reference to a value owned by main() can't be sent to a spawned thread:
// No-op function that statically proves we have an &i32.
fn opaque(_: &i32) {}
fn main() {
let x = 0i32;
std::thread::spawn(|| opaque(&x)); // E0373
}
This doesn't fail because &x is not Send (it is), but because std::thread::spawn() requires that the closure is 'static, and it isn't if it captures a reference to something that doesn't have static lifetime. The compiler gives us this hint along with the error:
note: function requires argument type to outlive `'static`
We can prove this by obtaining a reference with static lifetime (&'static i32) and sending it to a thread, which does work:
fn opaque(_: &i32) {}
fn main() {
static X: i32 = 0;
std::thread::spawn(|| opaque(&X));
}

Rust static lifetime conflicting anonymous

I'm trying to mock a trait for testing, but ATM not able to implement a function.
I use the crate mockall.
Error msg is:
cannot infer an appropriate lifetime due to conflicting requirements
but, the lifetime must be valid for the static lifetime...
expected `&mut __get_mapping::Expectation<'_>`
found `&mut __get_mapping::Expectation<'static>`
I'm aware that the problem is, a lifetime conflict.
But the item passed to the closure already has an anonymous lifetime, even if I do not state it explicitly.
I tried to find some examples with a solution or hints....
But I could not find a solution.
Is there a way to specify that the returning item has a lifetime other than static?
I also tried specifying the lifetime of the return type of the closure, but the error was still the same.
My code so far is:
#[mockall::automock]
pub trait Analyzer {
//...
fn get_mapping<'a>(&'a self, old: &Item) -> Option<&'a Item>;
//...
}
fn test() {
let mut analyzer = MockAnalyzer::new();
analyzer.expect_get_mapping().returning(|item:&'_ Item| Some(item));
// also tried ... returning(|item:&'_ Item| -> Option<&'_ Item> {Some(item)})
// my initial code was ... returning(|item| Some(item))
//...
}
If your Item is Clone, you might get away with the following:
analyzer
.expect_get_mapping()
.returning(|item: &'_ Item| Some(Box::leak(Box::new(item.clone()))));
This does indeed leak heap memory, so if your test code executes this more than a few 10 million times, it may cause trouble.

Why does passing tokio_postgres::Transaction as a reference ask to indicate the anonymous lifetime?

I'm using tokio_postgres to connect to a database and trying to start a transaction
let trans = client.transaction().await.unwrap();
trans.query("select * from abc", &[]).await.unwrap();
// ...
trans.commit().await.unwrap();
Everything works as expected. Now I want to put the code between trans.query and trans.commit into a separate function
async fn tx_work(trans: &tokio_postgres::Transaction) {
trans.query("select * from abc", &[]).await.unwrap();
// ...
trans.commit().await.unwrap();
}
and call it in main:
let trans = client.transaction().await.unwrap();
tx_work(&trans).await.unwrap();
The code doesn't compile:
error[E0726]: implicit elided lifetime not allowed here
--> src/abc.rs:209:28
|
209 | async fn tx_work(trans: &tokio_postgres::Transaction) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
This didn't help:
async fn tx_work<'a>(trans: &'a tokio_postgres::Transaction)
What do I do?
Based on the definition of Transaction it seems you want the lifetime specifier/parameter on the struct itself, not on the function parameter reference:
async fn tx_work(trans: &tokio_postgres::Transaction<'_>)
That's using the anonymous lifetime, but you can also explicitly specify the lifetime parameter:
async fn tx_work<'a>(trans: &tokio_postgres::Transaction<'a>)
It is common to relate these lifetimes to other existing lifetimes, for example, if you already had an explicit lifetime elsewhere and it makes sense to do so, you might pass it as the parameter directly.
This is because tokio_postgres::Transaction does not fully specify the type anymore than Vec would (compared to Vec<u8>), i.e. the lifetime specifiers are part of the type name, so you need tokio_postgres::Transaction<'some_lifetime>, but apparently you can use the anonymous lifetime '_ too.
More specifically, here, the lifetime parameter on Transaction pertains to the lifetime of the references contained within the Transaction struct, whereas a lifetime on the reference to the Transaction struct (like you initially attempted) pertains to … well, the lifetime of that very reference.
If this is all still confusing, I encourage you to read the excellent chapter on lifetimes from the book. It is an integral part of the Rust programming paradigm.

Can I safely multithread something which isn't meant to be multithreaded?

I'm using a trait which isn't designed around multithreading (Cursive).
Now, while it's using multithreading, it's going to be behind a mutex, so it won't be able to be used at two threads at the same time.
What is rust trying to protect me against and can I do anything about it?
For sample reference, my sample code is:
extern crate cursive;
use cursive::Cursive;
use std::thread;
use std::sync::{Mutex,Arc};
fn main() {
let mut siv = Arc::new(Mutex::new(Cursive::default()));
let copy_siv = siv.clone();
thread::spawn(move || {
let mut new_siv = copy_siv.lock().unwrap();
});
(*(siv.lock().unwrap())).run();
}
The compiler complains at thread::spawn:
Error[E0277]: `(dyn cursive::traits::View + 'static)` cannot be sent between threads safely
--> src/main.rs:16:5
|
16 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `(dyn cursive::traits::View + 'static)` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `(dyn cursive::traits::View + 'static)`
What is rust trying to protect me against [...]
Something in what you're sending between threads contains a dyn cursive::traits::View trait object. This trait object is not Send. It needs to be Send because by putting it inside an Arc, you can no longer predict which thread will be responsible for destroying it, so it must be safe to transfer ownership between threads.
[...] can I do anything about it?
You haven't provided enough context to say for certain, but probably not.
You could maybe try using a plain borrowed reference (plus a threading library that supports scoped threads), but I can't say if that will work for you.
Why wouldn't Mutex make it sync? Isn't that the point of Mutex?
No. It can't make something thread-safe when it wasn't already thread-safe. Mutex just manages exclusive access to a value, it doesn't make that access from different threads safe. The only thing that can make a type thread-safe is the type in question.
Making a guess: the library was written such that it does not require thread safety, thus Arc cannot assume it's thread-safe, so it refuses to compile.
I don't know what your actual code is. But the following example replicate the exact error you have:
use std::thread;
use std::sync::{Mutex,Arc};
struct Cursive;
impl Default for Cursive {
fn default() -> Self {
Cursive
}
}
trait View{
fn run(&self);
}
impl View for Cursive{
fn run(&self){}
}
fn main() {
let mut siv:Arc<Mutex<dyn View>> = Arc::new(Mutex::new(Cursive::default()));
let copy_siv = siv.clone();
thread::spawn(move || {
let mut new_siv = copy_siv.lock().unwrap();
});
(*(siv.lock().unwrap())).run();
}
You can try it in playground. The error message:
error[E0277]: `dyn View` cannot be sent between threads safely
--> src/main.rs:21:5
|
21 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `dyn View` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `dyn View`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<dyn View>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::Mutex<dyn View>>`
= note: required because it appears within the type `[closure#src/main.rs:21:19: 23:6 copy_siv:std::sync::Arc<std::sync::Mutex<dyn View>>]`
= note: required by `std::thread::spawn`
Analysis and Solution
The error message explained everything to experienced users. For those new to the language, siv is a reference counted, mutex protected trait object. This object only known to be a View, the compiler have no evidence on whether or not it is Send. However, for the code to work,
Arc<Mutex<T>> must be Send, as you are sending such a thing to another thread; Therefore:
Mutex<T> must be Send and Sync, as Arc requires the reference counted object to be Send and Sync. Therefore:
T must be Send, as the same object will be accessed in different threads without any further protection.
So, this code does not work. The solution is
let mut siv:Arc<Mutex<dyn View + Send>> = ...
You can try it yourself!
Mutex<T>: Send + Sync requires T: Send
To see why, first ask a question: what cannot be Send?
One example is that references to things with interior mutablity cannot be Send. Because if they were, people can mutate the thing through interior mutability in different threads and causes data race.
Now suppose you have a Mutex<&Cell<T>>, because the protected thing is only a reference, not the Cell itself, the Cell itself may still be somewhere unprotected. The compiler thus cannot conclude when you call lock().set() there is no risk to cause data race. So the compiler prevent it from Send.
What if I have to ...
So we see that &Cell<T> is not Send, and so even it is protected in Mutex we still cannot use it in another thread. What can we do then?
This problem is actually not new. Almost all UI API have the same problem: the UI components were created in the UI thread, and so you cannot access them in any other threads. Instead, you have to schedule a routine to be run in the UI thread, and let the UI thread to access the component.
Fails to do so in other languages (.NET, Java...) will throw exceptions in the best, causing undefined behavior in the worst. Once again, Rust turns such violates into compile errors without special treatments (&Cell<T> have nothing to do with UI), this is really GOOD!
So, if this is what you wanted to do, you have to do the same thing: access the view object in the UI thread only. How to do so depends on the API you were using.

When do I need to specify explicit lifetimes in Rust?

If I have the two functions
// implicit
fn foo(x: &i32) {
}
// explicit
fn bar<'a>(x: &'a i32) {
}
When would foo return an error and bar be the correct function header? I'm confused as to why I would explicitly declare a lifetime:
The 'a reads ‘the lifetime a’. Technically, every reference has some
lifetime associated with it, but the compiler lets you elide them in
common cases.
I understand what a lifetime is, but what does explicitly specifying a lifetime 'a do for me? For reference I'm using the Rust book as reading material
Practically speaking, the #1 reason you'll have to write lifetime annotations is because the compiler asks you so. It will reject function signatures which are not covered by lifetime elision rules.
I assume you would like an simple example where lifetimes are mandatory. Imagine the following scenario:
struct Blah<'a> {
hoy: &'a u8
}
fn want_a_hoy(blah: &Blah) -> &u8 {
blah.hoy
}
The intention is obvious, but the compiler doesn't handle it:
<anon>:7:35: 7:38 error: missing lifetime specifier [E0106]
<anon>:7 fn want_a_hoy(blah: &Blah) -> &u8 {
^~~
<anon>:7:35: 7:38 help: see the detailed explanation for E0106
<anon>:7:35: 7:38 help: this function's return type contains a borrowed value, but
the signature does not say which one of `blah`'s 2 elided
lifetimes it is borrowed from
In this case, annotations solve the problem:
fn want_a_hoy<'a, 'b>(blah: &'b Blah<'a>) -> &'a u8 {
blah.hoy
}
Here you're specifying 'a twice (on Blah<'a> and &'a). This is the same lifetime! So what you're saying to the compiler here is: "This function takes a reference to a blah containing an inner reference. I will return something which lives exactly as long as the inner reference of the blah." In this case, the signature gives a strong hint that you're likely to return something coming from the innards of the blah.

Resources