Live data from Hacker News

Surelock: Deadlock-Free Mutexes for Rust

notes.brooklynzelenka.com

21–30 of 90 posts

Re: Surelock: Deadlock-Free Mutexes for Rust

#21
post #2

I agree with the author: it's a shame that TVars aren't catching on in more languages. They are a great idea from the database world, that we could use in the rest of computing, too.

The cross-fertilization of ideas across computer science domains is more limited than I think people assume. Databases are just one area that contains a lot of good ideas that never seem to leak into other parts of the software world.

Supercomputing is another domain that has deep insights into scalable systems that is famously so insular that ideas rarely cross over into mainstream scalable systems. My detour through supercomputing probably added as much to my database design knowledge as anything I actually did in databases.

Re: Surelock: Deadlock-Free Mutexes for Rust

#23

Earlier quoted context omitted.

There’s no global lock. There’s a linear MutexKey that a lock of Level >= N has to be acquired with. Aquiring it consumes MutexKey and hands you back MutexKey where Level is the N of the level you’re locking. There’s no priority inversion possible because locks can only ever be held in decreasing orders of priority - you can’t acquire a low priority lock and then a high priority lock since your remaining MutexKey won…

In the example it seems pretty clear to me that: Mutex::new(AppConfig::default()); ...is meant to be acquiring a mutex protecting some global config object, yes? That's what I'm calling a "global lock". > There’s no priority inversion possible because locks can only ever be held in decreasing orders of priority T1 T2 -- -- small_lock(); big_lock(); small_lock(); ...and now any other thread that needs big_lock() spins…

Usually a global lock is a lock that is taken outside all others and is taken for large parts of the runtime (or even, everywhere the thread isn't waiting on a condition variable, file descriptor and the like).

Mutex::new(AppConfig::default()) might very well be a small, leaf mutex.

Re: Surelock: Deadlock-Free Mutexes for Rust

#24
I really agree with jandrewrogers' point about the insularity of the database domain. While working on a custom C++ engine to handle 10M vectors in minimal RAM, I’ve noticed that many 'mainstream' concurrency patterns simply don't scale when cache-locality is your primary bottleneck.

In the DB world, we often trade complex locking for deterministic ordering or latch-free structures, but translating those to general-purpose app code (like what this Rust crate tries to do) is where the friction happens. It’s great to see more 'DB-style' rigour (like total ordering for locks) making its way into library design.

Re: Surelock: Deadlock-Free Mutexes for Rust

#25
post #2

I agree with the author: it's a shame that TVars aren't catching on in more languages. They are a great idea from the database world, that we could use in the rest of computing, too.

It is a big reason why I picked Scala3/Zio over Rust for my most recent project.

Re: Surelock: Deadlock-Free Mutexes for Rust

#27
I can't understand why address instability is a problem: if a Mutex is moved, then it can't be locked (because you need to hold a borrow while locked, which impedes moving), so using addresses is perfectly fine and there is absolutely no need to use IDs.

Also the fact that it doesn't detect locking the same mutex twice makes no sense: a static order obviously detects that and when locking multiple mutexes at the same level all you need to do is check for equal consecutive addresses after sorting, which is trivial.

Overall it seems like the authors are weirdly both quite competent and very incompetent. This is typical of LLMs, but it doesn't seem ZlLM-made.

Re: Surelock: Deadlock-Free Mutexes for Rust

#28
post #27

I can't understand why address instability is a problem: if a Mutex is moved, then it can't be locked (because you need to hold a borrow while locked, which impedes moving), so using addresses is perfectly fine and there is absolutely no need to use IDs. Also the fact that it doesn't detect locking the same mutex twice makes no sense: a static order obviously detects that and when locking multiple mutexes at the same…

Don't address introduce ambiguous locking order across attempts?

While not obviously problematic, that seems weird enough you would need to validate that it is explicitly safe.

Re: Surelock: Deadlock-Free Mutexes for Rust

#29

[flagged]

So tired of this sort of comment. LLMs are trained using (primarily, generally) online material. It sounds like online humans, in aggregate, plus or minus a bit of policy on the part of the model builders.

> It sounds like online humans, in aggregate

That's exactly the problem. It sounds like one aggregate person. It's quite unpleasant to read the same turns of phrase again and again and again, especially when it means that the author copped out of writing it themselves.

In fairness I think in this case they mostly did write it themselves.

Re: Surelock: Deadlock-Free Mutexes for Rust

#30

I'm intrigued! I was fighting deadlocks in some Java code this week, and I'm working on a Rust project to maybe replace some of that. One thing I didn't see in the post or the repo: does this work with async code? I couldn't find the "search" button on Codeberg, and tests/integration.rs didn't have any async. For embedded, I have had my eye on https://github.com/embassy-rs/embassy (which has an async runtime for embe…

IIUC, this crate has similar restrictions to the std Mutex. So it depends on what you mean by "work with async code."

First, lock acquisition seems to be a blocking method. And I don't see a `try_lock` method, so the naive pattern of spinning on `try_lock` and yielding on failure won't work. It'll still work in an async function, you'll just block the executor if the lock is contested and be sad.

Second, the key and guard types are not Send, otherwise it would be possible to send a key of a lower level to a thread that has already acquired a lock of a higher level, allowing deadlocks. (Or to pass a mutex guard of a higher level to a thread that has a key of a lower level.)

Therefore, holding a lock or a key across an await point makes your Future not Send.

Technically, this is fine. Nothing about Rust async in general requires that your Futures are Send. But in practice, most of the popular async runtimes require this. So if you want to use this with Tokio, for example, then you have to design your system to not hold locks or keys across await points.

This first restriction seems like it could be improved with the addition of an `AsyncLockable` trait. But the second restriction seems to me to be fundamental to the design.

Post reply on HN