I am having a struct Proc that I want to make overall threadsafe and pass between threads without fear.
However it complains when passing to a thread closure, theat NotNull<String> is not send, I figured out that mutex wouldn't help with that, I tried to unsafe implement Send on a wrapper, as above, but it still doesn't allow me to continue.
Questions: #1 is anything missing from the wrapper that could quicly make it send. #2 I've read that this means that I am dereferencing somewhere to a raw pointer, how can I figure out whhich line this is? #3 is there any type better suited for that then a wrapper?
unsafe impl Send does not provide thread safety; it is a promise from you that there is thread safety. You should not write it unless you have a precise, accurate explanation for why the type is thread safe even though the compiler doesn’t think so. Most likely, you do not need unsafe impl Send. Rust’s “fearless concurrency” is built on truthfulSend impls; untruthful ones are to be feared.
Now, the reason why your wrapper didn't let your program compile is that Stringalready correctly implements Send, so wrapping it doesn’t change anything. We need to see where the real problem is.
Please post the full text of the Send error you got. It will have details which we can help you interpret. And, if you can, please also share a complete (compilable) short program which demonstrates the error. It’s much easier to help if we can play with the program.
My understanding was that for simple memory Sync implies Send (at least logically), Sync without Send is only in cases where the data is bound to the thread identity (Thread lcoal storage, locked mutex etc.)
Creating a minimal project will take me a day, this is copied out from cargo build.
I understand that String is Send however NonNull is not, I am wondering how this type is intriduced because my struct doesn't have it.
I will upload a minimal program as soon I have it.
Logs of cargo build are below.
error[E0277]: `NonNull<cfg::TString>` cannot be sent between threads safely
--> src/proc.rs:140:23
|
140 | thread::spawn(move||{
| _________-------------_^
| | |
| | required by a bound introduced by this call
141 | | let _self=&arc_self.clone();
142 | | let mut status= ProcStatus::Stopped;
... |
225 | | };
226 | | });
| |_________^ `NonNull<cfg::TString>` cannot be sent between threads safely
|
= help: within `cfg::Cfg`, the trait `std::marker::Send` is not implemented for `NonNull<cfg::TString>`
note: required because it appears within the type `RawVector<cfg::TString>`
--> /root/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/shared_vector-0.4.4/src/vector.rs:37:12
|
37 | pub struct RawVector<T> {
| ^^^^^^^^^
note: required because it appears within the type `Vector<cfg::TString>`
--> /root/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/shared_vector-0.4.4/src/vector.rs:907:12
|
907 | pub struct Vector<T, A: Allocator = Global> {
| ^^^^^^
note: required because it appears within the type `cfg::Cfg`
--> src/cfg.rs:46:12
|
46 | pub struct Cfg {
| ^^^
= note: required for `std::sync::Mutex<cfg::Cfg>` to implement `Sync`
note: required because it appears within the type `webserver::proc::Proc`
--> src/proc.rs:41:12
|
41 | pub struct Proc {
| ^^^^
= note: required because it appears within the type `&webserver::proc::Proc`
= note: required for `std::sync::Arc<&webserver::proc::Proc>` to implement `std::marker::Send`
note: required because it's used within this closure
--> src/proc.rs:140:23
|
140 | thread::spawn(move||{
| ^^^^^^
note: required by a bound in `std::thread::spawn`
--> /root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/mod.rs:731:8
|
728 | pub fn spawn<F, T>(f: F) -> JoinHandle<T>
| ----- required by a bound in this function
...
731 | F: Send + 'static,
| ^^^^ required by this bound in `spawn`
That is often the case, but in this case, you have neither Sync nor Send.
The error message is telling you where it is. More directly:
NonNull<...> is not Send
which is relevant because it is contained by the type RawVector<T> from the shared_vector library, which is therefore not Send
which is contained by Vector<T>, which is therefore not Send
which is contained by your actual Cfg struct definition, not the one you shared with us.
It looks to me like Vectorshould implement Send and Sync — since it is not interior mutable, unlike the other types in that library — but it doesn't. Possibly this was overlooked by the library author. You could file an issue asking for it, or study the code, determine whether doing so would be sound, and send a patch if it is.
Or, you could use a different data type — just plain Vec<String>? It seems like shared_vector::Vector<String> is only useful if you're going to sometimes share that vector directly as opposed to sharing a data structure that contains it like your Proc.
Thanks Kevin for your advice my problem is now resolved.
Vec< String > worked, I had a hunch that Vec wouldn't offer any significant advantage over shared_vector in this context. Perhaps my intuition about this was incorrect, or maybe programming relies more on precise logic than statistical probabilities.
Following your advice I was able to compile the program.
I will check the repo of shared_vecotr is this have been discussed already, I am curious about how it could be usefull wihtout Send, I found this discussion generelly discussing the usefullness of sync without send Sync but not Send? - #11 by Kestrer.
“Wouldn’t offer any significant advantage” is a good principle with which to choose data types, but I would apply it towards preferring to use the types from the standard library, like Vec, rather than using types from third-party libraries, unless I know of a specific benefit to be gained from that third-party library.
Perhaps my intuition about this was incorrect, or maybe programming relies more on precise logic than statistical probabilities.
I would say both; “does this type implement the traits and functions I need” is a matter of precise logic, but there are still things to be estimated when choosing a library:
Does this library provide, not just the functionality I know I need now, but things I am likely to need in the future?
Will this library continue to be maintained (to the degree necessary for its role in my program?)
If it might not, how difficult will it be to replace with something else?
If it does, and I expect to need to request new features, is the maintainer likely to agree that those features are suitable additions?