-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Mutexes are recursive on windows, but not on unix #19962
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
How can this make the semantics of the |
Unfortunately the use std::sync::Mutex;
use std::mem;
fn main() {
let m = Mutex::new(4u);
let mut g1 = m.lock();
let mut g2 = m.lock();
let p1 = &mut *g1;
let p2 = &mut *g2;
mem::swap(p1, p2);
} On unix that code deadlocks, but on windows it executes just fine. |
Wait, Anyway, since you could have aliased |
|
Oh right, it has to be shared in the first place. Heh. |
What are the limitations of fast mutexes that prevent us from using them? |
@sivadeilra and I discussed this and he recommends just adding a flag and checking it manually on Windows. |
@retep998 I don't think there are any limitations (we're currently using them), this is just a surprising consequence of using them. @pythonesque yeah I suspect that |
According to the current code we use Critical Sections for Mutexes on Windows. |
Whoa! I had no idea that "fast mutexes" was a thing. I thought there were only inter-process mutexes and critical sections. It looks like the "fast mutexes" or "guarded mutexes" are only for drivers, and maybe not for userland code? Or at least I couldn't figure out how to use them. Do you have pointers to the source for MSVC's implementation, or how to use them? |
Yeah, the bits that made it seem like they were only for drivers was why I said we probably couldn't use them. Apparently critical sections are the fastest userland ones you should use. On a related note, it might be worth clarifying in the |
According to some debugging, on Windows 8.1 x64, MSVC uses |
And this is pretty conclusive. I did a test with two threads constantly locking and unlocking the same mutex. When I used |
On my beefy Win7 x64 gaming rig, I get a rock-solid 26ns for RW, and a fluctuating 70-80ns for Critical. Faster and more reliable. |
Oh wow, and they can't be acquired recursively either, so we wouldn't even need to do anything different from the other platforms. Good find! |
@pythonesque - Yep just tried acquiring an |
Hm, they look like they have other problems though:
Defaulting to an unfair lock doesn't seem like a good idea (unless your only goal is to win benchmarks). But if MSVC++ is doing it... |
We already use |
@thestinger, what's the simple solution you have in mind? (Storing an extra flag internally?) |
Some quick tests show that
SRWLock:
Each row is 100ms apart. CPU has 4 cores/threads. |
@huonw: If you write a semaphore on top of it and hard-wire the count at 1, it will deadlock. There is probably a better way to do it. I think the older mutex type is already non-recursive but I think it's missing the syscall free fast path. |
As of Windows Server 2003 SP1, |
After some clarification on IRC I have realized that fairness means low priority threads won't steal mutex lock time from higher priority threads. |
Apparently [ #![allow(unstable)]
use std::sync::{StaticRwLock, RW_LOCK_INIT};
static LOCK: StaticRwLock = RW_LOCK_INIT;
fn main() {
let _read = LOCK.read();
let _write = LOCK.write();
} |
Also adjusted some of the FFI definitions because apparently they don't use the long pointer prefix. Gives a free performance boost because `SRWLock` is several times faster than `CriticalRegion` on every Windows system tested. Fixes #19962
This behavioral difference should factor into the stabilization of the methods on
sync::Mutex
and how we'd like to word the documentation.For now though, this is a tracking issue as this difference in behavior was not originally intended.
cc @aturon
The text was updated successfully, but these errors were encountered: