0

I have a function that is supposed to search for primes within a given range. (The algorithm is not important; please ignore the fact that it is very inefficient.)

use std::thread;
use std::sync::Mutex;
use std::convert::TryInto;

/// Takes the search range as (start, end) and outputs a vector with the primes found within
/// that range.
pub fn run(range: (u32, u32)) -> Vec<u32> {
    let mut found_primes: Mutex<Vec<u32>> = Mutex::new(Vec::new());

    let num_threads: usize = 8;
    let num_threads_32: u32 = 8;
    let join_handles: Vec<thread::JoinHandle<()>> = Vec::with_capacity(num_threads);

    // ERROR: `found_primes` does not live long enough
    let vec_ref = &found_primes;
    for t in 0..num_threads_32 {

        thread::spawn(move || {
            let mut n = range.0 + t;
            'n_loop: while n < range.1 {
                for divisor in 2..n {
                    if n % divisor == 0 {
                        n += num_threads_32;
                        continue 'n_loop;
                    }
                }
                // This is the part where I try to add a number to the vector
                vec_ref.lock().expect("Mutex was poisoned!").push(n);

                n += num_threads_32;
            }

            println!("Thread {} is done.", t);
        });
    }

    for handle in join_handles {
        handle.join();
    }

    // ERROR: cannot move out of dereference of `std::sync::MutexGuard<'_, std::vec::Vec<u32>>`
    *found_primes.lock().expect("Mutex was poisoned!")
}

I managed to get it working with std::sync::mpsc, but I'm pretty sure it can be done just with mutexes. However, the borrow checker doesn't like it.

The errors are in comments. I (think I) understand the first error: the compiler can't prove that &found_primes won't be used within a thread after found_primes is dropped (when the function returns), even though I .join() all the threads before that. I'm guessing I'll need unsafe code to make it work. I don't understand the second error, though.

Can someone explain the errors and tell me how to do this with only Mutexes?

D. Pardal
  • 6,173
  • 1
  • 17
  • 37
  • Please remove all the irrelevant code and add the errors you are getting. – user2722968 Oct 31 '20 at 18:52
  • @user2722968 Most of the code is relevant and the errors are in comments. I edited my question; please read it. – D. Pardal Oct 31 '20 at 18:53
  • Your first error is answered here: [Parameter type may not live long enough (with threads)](https://stackoverflow.com/a/32092120) – kmdreko Oct 31 '20 at 19:03
  • The first error is solved by [How can I pass a reference to a stack variable to a thread?](/q/32750829/3650362) (or the link kmdreko posted, which also links there). The second one is not solved elsewhere, but it is [completely unrelated to the first one](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bf15fdd4ba0f95c310299197c9ef433a). I'm voting to close this as unfocused because the unique question is buried under all the thread stuff (which has been adequately answered elsewhere) so far that I doubt it will be useful for future readers. – trent Oct 31 '20 at 19:33

1 Answers1

3

The last error is complaining about trying to move the contents out of the mutex. The .lock() returns a MutexGuard that only yields a reference to the contents. You can't move from it or it would leave the mutex in an invalid state. You can get an owned value by cloning, but that shouldn't be necessary if the mutex is going away anyway.

You can use .into_inner() to consume the mutex and return what was in it.

found_primes.into_inner().expect("Mutex was poisoned!")

See this fix and the other linked fix on the playground.

kmdreko
  • 42,554
  • 6
  • 57
  • 106