Hello everyone,
Actually a rust beginner, please forgive me if i'm not clear enough or if information are missing.
I'm actually trying to implement a basic web service with actrix but i'm stuck with basic (i guess) threading problems.
I'm using the Rincon library, it provide a structure DatabaseSession
which use
Rc
to hold values.
I read that Rc is not thread safe and can't be used in this context. But i can't change the code provided by the library.
I tried to use Arc
to encapsulate my repository, thinking the compiler will create another reference to the DatabaseSession
(which use RC) instead of cloning it. But he does not agree with me .
The question is :
- How can I get around my problem ?
- How can I deal with codes that are not thread-safe ?
Thanks,
To expose my problem, I redacted this similar example:
use std::rc::Rc;
use std::string::String;
use std::thread;
// Simplified version of struct provided by an external library - https://github.com/innoave/rincon/blob/e0bde6c78e43668c3cad0b1dd07466dfdd6fa4eb/rincon_session/src/database_session.rs#L36
#[derive(Debug)]
pub struct DatabaseSession {
database_name: String,
// Here the Rc which cause the compilation error.
connector: Rc<String>, // I can't change this RC.
}
impl DatabaseSession {
fn new() -> Self {
let example = "test".to_string();
let inst: DatabaseSession = DatabaseSession {
database_name: "db".to_string(),
connector: Rc::new("test".to_string()),
};
inst
}
}
// Simplified version of my implementation of a repository
pub struct Repository {
session: DatabaseSession,
}
impl Repository {
fn new(session: DatabaseSession) -> Self {
return Repository {
session,
};
}
pub fn greet(&self) {
println!("Hello");
}
}
fn main() {
let session: DatabaseSession = DatabaseSession::new();
let repo = Repository::new(session);
thread::spawn(move || {
repo.greet();
});
}
Compilation error
error[E0277]: `std::rc::Rc<std::string::String>` cannot be sent between threads safely
--> src/main.rs:47:5
|
47 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `std::rc::Rc<std::string::String>` cannot be sent between threads safely
|
= help: within `Repository`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
= note: required because it appears within the type `DatabaseSession`
= note: required because it appears within the type `Repository`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Repository>`
= note: required because it appears within the type `[closure@src/main.rs:47:19: 49:6 repo:std::sync::Arc<Repository>]`
= note: required by `std::thread::spawn`
error[E0277]: `std::rc::Rc<std::string::String>` cannot be shared between threads safely
--> src/main.rs:47:5
|
47 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `std::rc::Rc<std::string::String>` cannot be shared between threads safely
|
= help: within `Repository`, the trait `std::marker::Sync` is not implemented for `std::rc::Rc<std::string::String>`
= note: required because it appears within the type `DatabaseSession`
= note: required because it appears within the type `Repository`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Repository>`
= note: required because it appears within the type `[closure@src/main.rs:47:19: 49:6 repo:std::sync::Arc<Repository>]`
= note: required by `std::thread::spawn`
error: aborting due to 2 previous errors
Real implementation compilation errors
error[E0277]: `std::rc::Rc<rincon_connector::http::JsonHttpConnector>` cannot be sent between threads safely
--> src/main.rs:76:16
|
76 | let addr = SyncArbiter::start(2, || DbExecutor(repo));
| ^^^^^^^^^^^^^^^^^^ `std::rc::Rc<rincon_connector::http::JsonHttpConnector>` cannot be sent between threads safely
|
= help: within `rincon_session::database_session::DatabaseSession<rincon_connector::http::JsonHttpConnector>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<rincon_connector::http::JsonHttpConnector>`
= note: required because it appears within the type `rincon_session::database_session::DatabaseSession<rincon_connector::http::JsonHttpConnector>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<rincon_session::database_session::DatabaseSession<rincon_connector::http::JsonHttpConnector>>`
= note: required because it appears within the type `dbstore::db::repository::host::HostRepository`
= note: required because it appears within the type `[closure@src/main.rs:76:38: 76:57 repo:dbstore::db::repository::host::HostRepository]`
= note: required by `<actix::sync::SyncArbiter<A>>::start`
error[E0277]: `std::rc::Rc<std::cell::RefCell<tokio_core::reactor::Core>>` cannot be sent between threads safely
--> src/main.rs:76:16
|
76 | let addr = SyncArbiter::start(2, || DbExecutor(repo));
| ^^^^^^^^^^^^^^^^^^ `std::rc::Rc<std::cell::RefCell<tokio_core::reactor::Core>>` cannot be sent between threads safely
|
= help: within `rincon_session::database_session::DatabaseSession<rincon_connector::http::JsonHttpConnector>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::RefCell<tokio_core::reactor::Core>>`
= note: required because it appears within the type `rincon_session::database_session::DatabaseSession<rincon_connector::http::JsonHttpConnector>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<rincon_session::database_session::DatabaseSession<rincon_connector::http::JsonHttpConnector>>`
= note: required because it appears within the type `dbstore::db::repository::host::HostRepository`
= note: required because it appears within the type `[closure@src/main.rs:76:38: 76:57 repo:dbstore::db::repository::host::HostRepository]`
= note: required by `<actix::sync::SyncArbiter<A>>::start`
```