Sending Nalgebra VectorN between threads

Viewed 314

I'm using Nalgebra's VectorN<f64, N> type in some single-threaded code which is working well. I'm now trying to multithread various parts of the algorithm, but have run into issues passing VectorNs into a thread::spawn call. For example, the following code fails to compile:

use std::thread;
use nalgebra::{VectorN, DefaultAllocator, DimName};
use nalgebra::allocator::Allocator;

struct Test<N>
where
    N: DimName,
    DefaultAllocator: Allocator<f64, N>,
{
    pub field: VectorN<f64, N>,
}

impl<N> Test<N>
where
    N: DimName,
    DefaultAllocator: Allocator<f64, N>,
{
    pub fn test(&self) {
        let handle = thread::spawn(move || {
            let thing = self.field;

            let thing2 = thing * 2.0;

            thing2
        });

        let res = handle.join().unwrap();
    }
}

With this error:

error[E0277]: `<nalgebra::base::default_allocator::DefaultAllocator as nalgebra::base::allocator::Allocator<f64, N>>::Buffer` cannot be sent between threads safely
  --> trajectories/src/path/mod.rs:34:22
   |
34 |         let handle = thread::spawn(move || {
   |                      ^^^^^^^^^^^^^ `<nalgebra::base::default_allocator::DefaultAllocator as nalgebra::base::allocator::Allocator<f64, N>>::Buffer` cannot be sent between threads safely
   |
   = help: within `nalgebra::base::matrix::Matrix<f64, N, nalgebra::base::dimension::U1, <nalgebra::base::default_allocator::DefaultAllocator as nalgebra::base::allocator::Allocator<f64, N>>::Buffer>`, the trait `std::marker::Send` is not
implemented for `<nalgebra::base::default_allocator::DefaultAllocator as nalgebra::base::allocator::Allocator<f64, N>>::Buffer`
   = note: required because it appears within the type `nalgebra::base::matrix::Matrix<f64, N, nalgebra::base::dimension::U1, <nalgebra::base::default_allocator::DefaultAllocator as nalgebra::base::allocator::Allocator<f64, N>>::Buffer>`
   = note: required by `std::thread::spawn`

I've tried various definitions for N and DefaultAllocator in the where clauses but haven't got far. Various search engines have turned up nothing useful around this issue.

If I replace VectorN<f64, N> with VectorN<f64, U3> (or any other U* type from Nalgebra), the above error goes away. I've read the Nalgebra generic programming guide however that seems out of date and perhaps not what I need; I don't want complete genericity, just the ability to use VectorN with any size bound. What trait bounds do I need to put on my struct so I can pass field into a thread?

1 Answers

I took a stab in the dark (based on the error messages given by the compiler) and managed to make this work by adding bounds to Allocator::Buffer like this:

use nalgebra::allocator::Allocator;

struct Test<N>
where
    N: DimName,
    DefaultAllocator: Allocator<f64, N>,
    <DefaultAllocator as Allocator<f64, N>>::Buffer: Send + Sync,
{
    pub field: VectorN<f64, N>,
}

// snip ...

I'm not sure this is the right way to do it and it certainly adds some noise, but it appears to now let me pass Nalgebra constructs into threads.

Related