Using the same variable at the same time in different threads [duplicate] - multithreading

This question already has answers here:
What are idiomatic ways to send data between threads?
(2 answers)
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed 3 years ago.
I'm currently moving a project from Python to Rust, and I ran into a small problem with the concept of ownership in Rust.
My main thread create a empty vector, then, I start another thread and that thread will run forever (loop) and add data to the vector every second. Until here, no problem.
The problem comes when from my main thread, I want to read the vector (print it or use the data inside it). Since the ownership has been moved, I can't use the vector in my main thread.
let mut prices: Vec<f64> = Vec::new();
thread::spawn(move || {
start_filling_prices(&mut prices);
});
println!("{:?}", prices);
^^^^^^^ value borrowed here after move
I've tried using a Mutex, Arc, Box, but the same problem occurs every time (or maybe I used the wrong one).
So, does someone know how to use the same variable in different threads at the same time?

Related

Reading a vector from multiple threads [duplicate]

This question already has an answer here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed last month.
I have a function that returns a vector of strings, which is read by multiple threads later. How to do this in rust?
fn get_list() -> Vec<String> { ... }
fn read_vec() {
let v = get_list();
for i in 1..10 {
handles.push(thread::spawn (|| { do_work(&v); }));
}
handles.join();
}
I think I need to extend the lifetime of v to static and pass it as a immutable ref to threads. But, I am not sure , how?
The problem you are facing is that the threads spawned by thread::spawn run for an unknown amount of time. You'll need to make sure that your Vec<String> outlives these threads.
You can use atomic reference-counting by creating an Arc<Vec<String>>, and create a clone for each thread. The Vec<String> will be deallocated only when all Arcs are dropped. Docs
You can leak the Vec<String>. I personally like this approach, but only if you need the Vec<String> for the entire runtime of your program. To achieve this, you can turn your Vec<String> into a &'static [String] by using Vec::leak. Docs
You can ensure that your threads will not run after the read_vec function returns - This is what you're essentially doing by calling handles.join(). However, the compiler doesn't see that these threads are joined later, and there might be edge cases where they are not joined (what happens when the 2nd thread::spawn panics?). To make this explicit, use the scope function in std::thread. Docs
Of course, you can also just clone the Vec<String>, and give each thread a unique copy.
TL;DR:
For this particular use-case, I'd recommend std::thread::scope. If the Vec<String> lives for the entire duration of your program, leaking it using Vec::leak is a great and often under-used solution. For more complex scenarios, wrapping the Vec<String> in an Arc is probably the right way to go.

rust mutex borrowed value does not live long enough [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 9 months ago.
Improve this question
enter image description here
I want lock multiple page before executor action ,how do?
First, from the code it looks like it's possible to hit the same entry multiple times. This means you'll immediately deadlock, as the second access will try to lock a mutex which is already locked. You should probably use or_insert_with in order to only acquire the lock if there was no entry for that key.
Second, well MutexGuard (whether that of tokio or the stdlib) borrows the mutex. Since the Mutex is only borrowed for the span of the iteration, the MutexGuard can't outlive that. The way to fix that is to expand the Mutex's lifetime e.g. by adding it to a collection that's outside the iteration then borrowing that. At which point you probably need two iterations, because if you push a lock into the "owner" collection then immediately borrow that, the collection will be borrowed on the next iteration and you won't be able to insert a new item:
let mut locks = vec![];
let mut page_map = HashMap::new();
for key in keys {
let page = store.get(key).unwrap();
locks.push((key, page.clone()));
}
for (key, lock) in &locks {
page_map.entry(key).or_insert_with(|| lock.lock());
}
Although then you're hitting the third issue (and second likelyhood of deadlock): if this can be executed twice concurrently it's possible for two calls to have key_feature_map in different order, meaning one call might lock page A then try to acquire page B, while a second call will have locked page B and now try to acquire page A.
Both calls are waiting on the other's lock, so they'll be deadlocked.

Collecting an iterator of threads into a vector start the threads

The following snippet shows mapping an iterator into threads and collecting into a Vec
let workers = input
.chunks(chunk_size)
.map(|chunk| {
let lines = chunk.iter().map(|s| s.to_string()).collect::<Vec<_>>();
thread::spawn(move || count_letters(&lines))
})
.collect::<Vec<_>>();
Won't this start all threads running (up to the os creating them)? In other words, there is no real limit to how many threads will be created aside from the length of input.
Assuming this is true, if one wanted to do this pattern without instantiating all the threads upon collect, might one use another closure i.e. thread::spawn(move || count_letters(&lines)) -> || thread::spawn(move || count_letters(&lines)) and would this be the rust style?
Won't this start all threads running (up to the os creating them)?
Yes. Technically the collect is not even necessary here, a for would do.
Assuming this is true, if one wanted to do this pattern without instantiating all the threads upon collect, might one use another closure
But then... why bother with the spawn, or the two closures? You can just put that where you'd call the outer closure.
would this be the rust style?
The rust style would be to use rayon, probably.
If you wanted to do that by hand, then the usual: create a queue (an mpmc channel of some sort, possibly bounded), spawn however many workers you have feeding from the queue, push all your work on the queue, then collect the results somehow.

Is there a way to spawn a thread with a specified lifetime in Rust? [duplicate]

This question already has an answer here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed 2 years ago.
I'm quite new to Rust, so I've encountered a few things I'm not used to. One issue that's causing me some grief is related to threads.
I would like to spawn a thread that executes a struct's method, but I'm not able to because the method needs to have a 'static lifetime. I'd prefer the method (and by extension the struct) didn't have a 'static lifetime.
If I know for certain that the thread will exit before the struct's instantiated value is dropped, is there a way to communicate this with Rust? In other words, can I tell Rust that I can guarantee the value will not have been dropped until after the thread exits? Or perhaps is there a way to pass a lifetime to a thread?
If none of this is possible, what can be done instead? I've looked into making the code asynchronous instead, but haven't had any success in fixing the issues described above.
If the method and struct must have a 'static lifetime, how might I go about appropriately specifying this?
Here's a simplified example of the problem:
pub struct Thing {
value: i32,
}
impl Thing {
pub fn new(value: i32) -> Thing {
Thing {
value,
}
}
fn in_thread(&self) {
println!("in thread");
// do things that block the thread
}
pub fn spawn_thread(&self) {
std::thread::spawn(move || {
self.in_thread(); // problem occurs here
});
}
}
If none of this is possible, what can be done instead? I've looked into making the code asynchronous instead, but haven't had any success in fixing the issues described above.
I wouldn't recommend to pass data via references to other threads. Instead, try to design your program so that the thread can own the data. You can do this by either move in the data when spawning a thread, alternatively, you may want to pass data via a Channel.

How can Rust be told that a thread does not live longer than its caller? [duplicate]

This question already has an answer here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed 5 years ago.
I have the following code:
fn main() {
let message = "Can't shoot yourself in the foot if you ain't got no gun";
let t1 = std::thread::spawn(|| {
println!("{}", message);
});
t1.join();
}
rustc gives me the compilation error:
closure may outlive the current function, but it borrows message, which is owned by the current function
This is wrong since:
The function it's referring to here is (I believe) main. The threads will be killed or enter in UB once main is finished executing.
The function it's referring to clearly invokes .join() on said thread.
Is the previous code unsafe in any way? If so, why? If not, how can I get the compiler to understand that?
Edit: Yes I am aware I can just move the message in this case, my question is specifically asking how can I pass a reference to it (preferably without having to heap allocate it, similarly to how this code would do it:
std::thread([&message]() -> void {/* etc */});
(Just to clarify, what I'm actually trying to do is access a thread safe data structure from two threads... other solutions to the problem that don't involve making the copy work would also help).
Edit2: The question this has been marked as a duplicate of is 5 pages long and as such I'd consider it and invalid question in it's own right.
Is the previous code 'unsafe' in any way ? If so, why ?
The goal of Rust's type-checking and borrow-checking system is to disallow unsafe programs, but that does not mean that all programs that fail to compile are unsafe. In this specific case, your code is not unsafe, but it does not satisfy the type constraints of the functions you are using.
The function it's referring to clearly invokes .join() on said thread.
But there is nothing from a type-checker standpoint that requires the call the .join. A type-checking system (on its own) can't enforce that a function has or has not been called on a given object. You could just as easily imagine an example like
let message = "Can't shoot yourself in the foot if you ain't got no gun";
let mut handles = vec![];
for i in 0..3 {
let t1 = std::thread::spawn(|| {
println!("{} {}", message, i);
});
handles.push(t1);
}
for t1 in handles {
t1.join();
}
where a human can tell that each thread is joined before main exits. But a typechecker has no way to know that.
The function it's referring to here is (I believe) main. So presumably those threads will be killed when main exists anyway (and them running after main exists is ub).
From the standpoint of the checkers, main is just another function. There is no special knowledge that this specific function can have extra behavior. If this were any other function, the thread would not be auto-killed. Expanding on that, even for main there is no guarantee that the child threads will be killed instantly. If it takes 5ms for the child threads to be killed, that is still 5ms where the child threads could be accessing the content of a variable that has gone out of scope.
To gain the behavior that you are looking for with this specific snippet (as-is), the lifetime of the closure would have to be tied to the lifetime of the t1 object, such that the closure was guaranteed to never be used after the handles have been cleaned up. While that is certainly an option, it is significantly less flexible in the general case. Because it would be enforced at the type level, there would be no way to opt out of this behavior.
You could consider using crossbeam, specifically crossbeam::scope's .spawn, which enforces this lifetime requirement where the standard library does not, meaning a thread must stop execution before the scope is finished.
In your specific case, your code works fine as long as you transfer ownership of message to the child thread instead of borrowing it from the main function, because there is no risk of unsafe code with or without your call to .join. Your code works fine if you change
let t1 = std::thread::spawn(|| {
to
let t1 = std::thread::spawn(move || {

Resources