2

I have a bucket of objects that need to accumulate values. It's protected by an RwLock, and as such I also keep around its write lock. I want to keep a single write lock for the duration of the process.

For example:

use std::sync::RwLock;

fn main() {
    let locked = RwLock::new(Vec::<u32>::new());

    // this is the entry point for real-world code
    let mut writer = locked.write().unwrap();    

    // copy into 'locked' until it is full (has 4 items)
    for v in 0..100 {
        if writer.len() > 4 {
            // discard 'writer' and 'locked', create anew
            locked = RwLock::new(Vec::<u32>::new());
            writer = locked.write().unwrap();
        }
        writer.push(v);
    }
}

While my example operates on fixed data, and so appears to not need the RwLock at all, the real code would enter at "real code" and not necessarily exit on the boundary of locked becoming "full".

How do I create a new locked and writer object when needed without the borrow-checker disagreeing?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
njaard
  • 529
  • 4
  • 15
  • I don't see why you have to discard the vector and the lock around it. Why not just change its size to zero to discard all the data in it? – David Grayson Aug 04 '16 at 20:16
  • I see your disclaimer, but I still don't understand your program. If you hold a writer lock for the duration of the entire program, then a reader lock can never be obtained, thus there isn't really any possibility for multithreading... – Shepmaster Aug 04 '16 at 20:39

1 Answers1

3

I agree with David Grayson, there's no obvious need to recreate the RwLock. Assuming you need the vector after filling it up, use mem::replace to switch out the Vec:

use std::sync::RwLock;
use std::mem;

fn main() {
    let locked = RwLock::new(Vec::<u32>::new());
    let mut writer = locked.write().unwrap();    

    for v in 0..100 {
        if writer.len() > 4 {
            let old_vec = mem::replace(&mut *writer, Vec::new());
        }
        writer.push(v);
    }
}

If you don't need the Vec, then just call Vec::clear.

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • `mem::replace` is documented as not copying any of its parameters, but its source code uses [using copy_non_overlapping](https://doc.rust-lang.org/std/ptr/fn.copy_nonoverlapping.html). I need this code to work with `Drop` and it's unclear when I'm allowed to do that. I created a new question here. – njaard Aug 04 '16 at 23:27
  • 1
    I think the documentation should say "without cloning" or "without deep-copying". `mem::replace` calls `mem::swap` which correctly uses `mem::forget` in order to prevent extra drops, so you shouldn't have any problems. Anyway the code in this answer doesn't mention `unsafe`, so you know it won't have extra drops without even looking at the source :) – durka42 Aug 23 '16 at 16:04