robinz
June 24, 2020, 6:09pm
1
Hi everyone, I am a beginner of Rust. And now I encounter a problem on impl "Send" for trait object when using with tokio.
The code is the following:
use async_trait::async_trait;
use tokio::io::{AsyncRead, AsyncWrite};
#[async_trait]
pub trait Handler {
async fn handle(&self) -> Result<(), std::io::Error>;
}
async fn serve( handler: std::sync::Arc<dyn Handler + Send>) {
tokio::spawn(async move {
let handler = handler;
Ok(())
});
}
fn main(){}
The error message is
error[E0277]: `dyn Handler + std::marker::Send` cannot be shared between threads safely
--> src/main.rs:10:5
|
10 | tokio::spawn(async move {
| ^^^^^^^^^^^^ `dyn Handler + std::marker::Send` cannot be shared between threads safely
|
::: /Users/fbzhong/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/task/spawn.rs:127:21
|
127 | T: Future + Send + 'static,
| ---- required by this bound in `tokio::task::spawn::spawn`
|
Can anyone help me on this?
Thanks.
The solution offered by https://github.com/dtolnay/async-trait#dyn-traits is to add Send
as a supertrait of the trait you're making into a trait object, rather than to add it as a bound. I think that'd look roughly like
...
#[async_trait]
pub trait Handler: Send {
async fn handle(&self) -> Result<(), std::io::Error>;
}
async fn serve( handler: std::sync::Arc<dyn Handler>) {
...
Does this work for your use case / is this bound acceptable? If so, I think that's the best solution.
1 Like
robinz
June 24, 2020, 6:54pm
3
Hi @daboross Thanks for replying. And I did try this method, and it have errors too:
error[E0277]: `dyn Handler` cannot be shared between threads safely
--> src/main.rs:9:5
|
9 | tokio::spawn(async move {
| ^^^^^^^^^^^^ `dyn Handler` cannot be shared between threads safely
|
::: /Users/fbzhong/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/task/spawn.rs:127:21
|
127 | T: Future + Send + 'static,
| ---- required by this bound in `tokio::task::spawn::spawn`
|
Can you please take a look at this again? Really appreciate!
The code is
use async_trait::async_trait;
#[async_trait]
pub trait Handler: Send {
async fn handle(&self) -> Result<(), std::io::Error>;
}
async fn serve( handler: std::sync::Arc<dyn Handler>) {
tokio::spawn(async move {
let handler = handler;
Ok(())
});
}
fn main(){}
CAD97
June 24, 2020, 7:09pm
4
robinz:
cannot be shared
I believe this is referring to the Sync
trait, not Send
.
robinz
June 24, 2020, 7:12pm
5
Hi @CAD97 ,
I just tried "Sync" trait, same error
tokio::spawn
requires both Send
and Sync
, so if you only specify one (regardless of which one) you'll get a similar error. Requiring both should work:
pub trait Handler: Send + Sync {
There's another error in compilation, but that should also be easy to resolve. It can't tell the error type for the closure, so you need to specify it explicitly with Ok::<(), ()>(())
(using ()
for the error type) rather than Ok(())
, or otherwise give it that information. With that change and Send + Sync
, the example compiles for me.
2 Likes
robinz
June 24, 2020, 7:21pm
7
Awesome! It works! Thank you so much!
alice
June 25, 2020, 5:05am
8
Note that it is not true that tokio::spawn
requires both; in fact it requires only Send. It's just that an Arc<T>
is not Send unless T is both Send and Sync.
3 Likes
robinz
June 25, 2020, 7:18am
9
Oh, that explains the error [E0277]
127 | T: Future + Send + 'static,
| ---- required by this bound in `tokio::task::spawn::spawn`
|
Great to know! Thank you very much!
1 Like
system
Closed
September 23, 2020, 7:18am
10
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.