Skip to main content

How to Create a Lock File (Mutex) in Batch Script

In computer science, a Mutex (Mutual Exclusion object) is a synchronization primitive that prevents two processes from accessing the same resource at the same time. While Batch doesn't have a native "Mutex" class like higher-level languages, we can simulate this behavior using a "Lock File." This technique ensures that only one "owner" can hold the lock, while all others must either wait or abort.

This guide will explain how to implement a reliable file-based Mutex in your Batch scripts to protect sensitive operations.

The Basic Logic of a File Mutex

A file-based Mutex relies on the operating system's ability to enforce exclusive file access. The script attempts to acquire an exclusive handle on a file; if another process already holds it, the attempt fails.

Implementation: Redirect-Based Lock

@echo off
set "MutexFile=%temp%\app_%~n0.lock"
set "Locked=0"

:: Attempt to acquire an exclusive lock using robust file descriptor 9
:: The OS enforces that only one process can hold the redirect handle
(
set "Locked=1"
echo [OK] Mutex acquired. Performing protected work...

rem === Your protected logic goes here ===
timeout /t 5 /nobreak >nul
echo Work complete.
rem === End of protected logic ===

) 9>"%MutexFile%" 2>nul

if "%Locked%"=="0" (
echo [BLOCKED] Another instance is already holding the Mutex.
echo Wait for it to finish or check for stale processes.
pause
exit /b 1
)

:: Clean up the lock file after the handle is released
del "%MutexFile%" >nul 2>&1
info

Why redirect locking works. By redirecting stderr (2>) to the lock file and placing all protected logic inside the parenthesized block, the operating system holds an exclusive file handle for the entire duration. If a second instance tries to redirect to the same file, the OS denies access. When the first instance exits, even via crash, Ctrl+C, or window close, the OS releases the handle automatically. No stale locks.

Method 2: The "Directory Lock" (Atomic Creation)

Expert scripters often use a Directory as a lock instead of a file. This is because the mkdir command is highly "Atomic" in Windows, if two scripts run mkdir at the exact same millisecond, only one will succeed, while the other will get an error.

@echo off
setlocal

set "LockDir=%temp%\Lock_%~n0"

:: Try to create the directory (atomic operation)
mkdir "%LockDir%" 2>nul

if %errorlevel% neq 0 (
echo [LOCKED] Failed to acquire Directory Mutex.
echo.

rem Check if the lock might be stale
if exist "%LockDir%" (
powershell -NoProfile -Command ^
"$age = (Get-Date) - (Get-Item '%LockDir%').CreationTime;" ^
"if ($age.TotalMinutes -gt 10) {" ^
" Write-Host '[INFO] Lock is over 10 minutes old. It may be stale.';" ^
" Write-Host ' Delete %LockDir% manually if the previous instance is gone.'" ^
"}"
)

pause
exit /b 1
)

echo [OK] Directory Mutex acquired.

:: === Your protected logic goes here ===
echo Working...
timeout /t 5 /nobreak >nul
echo Work complete.
:: === End of protected logic ===

:: Release the lock
rd "%LockDir%" 2>nul

if %errorlevel% neq 0 (
echo [WARNING] Could not release the lock directory.
)

echo [OK] Mutex released.

pause
endlocal
tip

Using mkdir for a Mutex is superior to if exist checks because there is no "gap" between checking and creating where a second process could sneak in. However, unlike redirect locking, directory locks are not automatically released on crash, see the stale-lock detection above.

Method 3: Named Mutex via PowerShell (System-Level)

For mission-critical scripts or multi-user environments, a named mutex provides kernel-level synchronization that works across all sessions.

@echo off
set "MutexName=Global\BatchMutex_%~n0"

:: Attempt to acquire a system-wide named mutex
powershell -NoProfile -Command ^
"$created = $false;" ^
"$mutex = New-Object System.Threading.Mutex($true, '%MutexName%', [ref]$created);" ^
"if (-not $created) {" ^
" if (-not $mutex.WaitOne(0)) {" ^
" Write-Host '[BLOCKED] Another instance holds the mutex.';" ^
" $mutex.Dispose();" ^
" exit 1" ^
" }" ^
"};" ^
"Write-Host '[OK] Mutex acquired.';" ^
"exit 0"

if %errorlevel% neq 0 (
pause
exit /b 1
)

:: === Your protected logic goes here ===
echo [ACTION] Performing exclusive work...
timeout /t 10 /nobreak >nul
echo Work complete.
:: === End of protected logic ===

:: Release the mutex
powershell -NoProfile -Command ^
"try {" ^
" $mutex = [System.Threading.Mutex]::OpenExisting('%MutexName%');" ^
" $mutex.ReleaseMutex(); $mutex.Dispose();" ^
" Write-Host '[OK] Mutex released.'" ^
"} catch { Write-Host '[INFO] Mutex was already released.' }"

Best Practices and Security Rules

1. Choose the Right Method

  • Redirect Lock (Method 1): Best for local single-user scripts. Automatically releases on crash. Simplest and most reliable.
  • Directory Lock (Method 2): Best when file-based locking is unreliable (AV interference, network shares). Atomic creation but requires stale-lock handling.
  • Named Mutex (Method 3): Best for multi-user, multi-session, or mission-critical scenarios requiring kernel-level guarantees.

2. Mutex Scope

If your script manages a global resource (like a database), keep the lock in a shared location or use a Global\ mutex prefix. If it's a per-user task, keep it in %temp%.

3. Clear Naming

Do not use generic names like lock.txt. Include the script name using %~n0 to automatically generate unique, identifiable lock names.

How to Avoid Common Errors

Wrong Way: Using "if exist" to check before creating

:: RACE CONDITION: Two instances can both pass this check simultaneously
if exist "%lock%" exit /b
echo locked > "%lock%"

Correct Way: Use an atomic operation, redirect locking (Method 1), mkdir (Method 2), or a named mutex (Method 3). These ensure that the check and the acquisition happen as a single indivisible operation.

Problem: Antivirus Interference

Some aggressive Antivirus software might "lock" your .lock file to scan it when it's created, potentially causing your own script's del command to fail with "Access Denied."

Best Practice: Use the Directory Lock method (mkdir) to avoid AV file-scanning triggers, or use the redirect method where the OS manages the handle.

Conclusions

Implementing a Mutex via a lock file or directory is a critical step for any Batch script that manages state or shared resources. By choosing the atomic redirect approach, the mkdir directory lock, or the kernel-level named mutex, you create a robust synchronization layer that prevents data corruption and redundant execution. These techniques ensure your automation scripts behave predictably even in complex, multi-user environments.