A simple wrapper for creating and locking Windows named system mutexes via the windows crate.
- Create global (machine-wide) or local (session-scoped) named mutexes
- Acquire locks with an optional timeout
- RAII-style
WinSystemMutexGuardthat automatically releases the mutex when dropped
Add win-mutex to your Cargo.toml:
[dependencies]
win-mutex = { git = "https://github.com/rgbav/win-mutex" }A crate may be provided in the future.
use win_mutex::{WinSystemMutex, MutexIdentifier, LockTimeout};
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create (or open) a global, machine-wide named mutex
let mutex = WinSystemMutex::new(MutexIdentifier::Global("MyAppMutex".to_string()))?;
// Try to acquire the lock, waiting up to 5 seconds
let _guard = mutex.try_lock(LockTimeout::After(Duration::from_secs(5)))?;
println!("Mutex acquired – only one instance can be here at a time.");
// _guard is dropped here, automatically releasing the mutex
Ok(())
}A common use-case is preventing multiple instances of an application from running at the same time:
use std::process::exit;
use std::time::Duration;
use win_mutex::{LockTimeout, WaitError, WinSystemMutex, MutexIdentifier};
fn main() {
let mutex = WinSystemMutex::new(
MutexIdentifier::Global("dcf25dfb-ed09-43a7-b3b5-83c0065e89f4".to_string())
).expect("Failed to create mutex");
match mutex.try_lock(LockTimeout::After(Duration::from_secs(5))) {
Ok(_guard) => {
println!("Running as the only instance.");
// ... application logic ...
}
Err(WaitError::Timeout) => {
println!("Another instance is already running. Exiting.");
exit(0);
}
Err(WaitError::Failed(code)) => {
println!("Failed to acquire mutex (error code: {code}). Exiting.");
exit(1);
}
}
}use win_mutex::{WinSystemMutex, MutexIdentifier};
// Elevated service or administrator process — creates the mutex
// with a NULL DACL so that standard-user processes can open it.
let mutex = WinSystemMutex::new_permissive(
MutexIdentifier::Global("my-app-guid".to_string())
)?;
// Standard desktop application — opens the same mutex without needing
// elevated rights, because the NULL DACL permits all access.
let mutex = WinSystemMutex::new(
MutexIdentifier::Global("my-app-guid".to_string())
)?;Security note: A NULL DACL removes all access control from the kernel object. Only use
new_permissivefor coordination primitives (mutexes), not for objects that guard sensitive data.
If a process terminates while holding the mutex (e.g. due to a panic or crash), Windows marks it as abandoned. The next caller of try_lock will still acquire the lock and receive Ok(guard) — the underlying WaitForSingleObject returns WAIT_ABANDONED in this case, which this crate treats as a successful acquisition.
This means you should always consider that the protected resource may be in an inconsistent state when taking over an abandoned mutex.
MIT – see LICENSE for details.