dospro
dospro

Reputation: 490

Move an iterator with a reference into a thread

I have a type that represents a file. For simplicity lets say the type holds a buffer with the contents of the file.

There is also a method for building an iterator which holds a reference to the internal buffer.

The file-type is created on the main thread, but I need to "send" the iterator into the thread.

Let me show what I am trying to do

struct FileType {...}

let mut my_file_type = FileType::new("some_filename");
let mut my_iterator = my_file_type.iter();

external_library_object.start_process(move|_| {
    for _ in (0..10) {
        println!(my_iterator.next().unwrap());
    }
}

external_library_object (which by the way is cpal's device) is... well an object from a library I can't change. The closure parameter implements Send trait though.

This doesn't work because my_file_type doesn't live long enough. So I tried a combination of Mutex (so the iterator is mutable) and Arc(so we share the iterator between the 2 threads)

...

let mut my_file_type = FileType::new("some_filename");
let mut my_iterator = Arc::new(Mutex::new(my_file_type.iter()));

external_library_object.start_process(move|_| {
    let mut cloned = my_iterator.clone();
    for _ in (0..10) {
        println!(cloned.lock().unwrap().next().unwrap());
    }
}

But again, this doesn't work. I get an error similar to this:

xx |     let mut my_iterator = Arc::new(Mutex::new(my_file_type.iter()));
   |                                               ^^^^^^^^^^^^-------
   |                                                   |
   |                                                   borrowed value does not live long enough
   |                                                   argument requires that `my_file_type` is borrowed for `'static`
...
xx | }
   | - `my_file_type` dropped here while still borrowed

I am kind of stuck here. Is there a way to use the iterator which has a reference to other object(a buffer in this case) inside a different thread?

Edit: In my specific case the itertor is infinite and the closure executes multiple times. That is the reason I can't move the entire FileType inside the thread.

Upvotes: 3

Views: 285

Answers (1)

Aloso
Aloso

Reputation: 5427

This is tricky, because the process borrows an iterator, which in turn borrows a struct. Putting just the iterator into an Arc<Mutex<>> is not sufficient, because this pointer might still outlive the FileType it borrows. However, we can't put both the FileType and the iterator into a reference-counted struct, since that struct would then be self-referential.

The easiest solution to this that I can think of (short of using scoped threads) is to create an iterator that owns the FileType, and then put it into a Arc<Mutex<>> (minimal playground example):

let my_file_type = FileType::new("test!");
let my_iterator = Arc::new(Mutex::new(my_file_type.into_iter()));

external_library_object.start_process(move |_| {
    for _ in 0..10 {
        println!("{:?}", my_iterator.lock().unwrap().next().unwrap());
    }
});

You just have to implement an owned iterator for your FileType struct, if it doesn't exist yet.

Upvotes: 0

Related Questions