How to idiomatically take a bunch of locks at once?

I have a bit of code where I have several (well, four) random samples and I want to lock all of them together and operate on the set. (The various locks are LockResult<RwLockWriteGuard<T>>, coming back from a function which selects them from a map.) I ended up with a block which starts like this:

                match northlock {
                    Ok(mut north) => {
                        match westlock {
                            Ok(mut west) => {
                                match southlock {
                                    Ok(mut south) => {
                                        match eastlock {
                                            Ok(mut east) => {

... which works but feels icky. Is there a cleaner syntax which accomplishes the same thing?

I would say that the idomatic way to express your pattern matching there is

match (northlock, westlock, southlock, eastlock) {
    (Ok(north), Ok(west), Ok(south), Ok(east)) => { }
    _ => {}
}
4 Likes

What are you doing on the Err side? If you're returning the error, then I would use the ? operator as you grab each lock. If you're panicking, I would unwrap/expect each one. If you're just ignoring it, then a 4-way match like @joelgallant suggested seems fine.

5 Likes

I'm currently panicking, but, actually, I think ignoring is probably actually fine, because as I understand it, the situation where it would be an error is if another writer thread panics while holding a write lock, and this is actually the only writer thread.

Well that certainly is much simpler. Needs to be

(Ok(mut north), Ok(mut west), Ok(mut south), Ok(mut east))

right? Anyway, this is handy because I'm returning a tuple of locks from a function anyway, and they don't need to be named.

I know you said you only write from one thread, but do mind your lock order if your readers also attempt multiple locks. One position's (south, east) corresponds to another's (west, north). With lock order NWSE, the former may obtain its south first while the latter obtains its north, and then they'll deadlock when the former tries east and the latter tries west. Using lock order NWES would be consistent, top-down left-right.

(I'm assuming a simple flat map -- if it's spherical or otherwise wraps, the lock order needs to deal with that too.)

Thanks — I think this is okay, because my readers just care about individual cell contents, and right now they're doing non-blocking reads, because it doesn't really matter if one cell is a frame late in getting updated. But I'll keep that in mind in case I change anything!

On another note, I switched to parking_lot's RwLock in implementation from the standard one, and that lets me run at about 10× faster. My first pass had a crossbeam queue where I pushed the updates, and that didn't scale up enough. I tried messing with some of the more sophisticated things like evmap and dashmap, but they weren't giving me quite what I want (plus dashmap seems to have a new major version every month), and it seems like the basically-naïve "big map of locks" is sufficient (I can run pretty fast and still have the thread sleep so it's not burning up the CPU).

1 Like

The std locks might someday switch to parking_lot, but there were issues -- see the attempt here:
https://github.com/rust-lang/rust/pull/56410

(There were integration issues -- not to discourage you from using it yourself.)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.