Interactively using Mutexes (et al) in Powershell
By default, powershell v2.0 (at the console, not the graphical ISE) uses an MTA threadpool. What this means is that each interactive line is executed on a different thread:
PS> [threading.thread]::CurrentThread.ManagedThreadId13PS> [threading.thread]::CurrentThread.ManagedThreadId10PS> [threading.thread]::CurrentThread.ManagedThreadId8PS> [threading.thread]::CurrentThread.ManagedThreadId4
However, a non-interactive script will run under a single thread, that is to say, the thread that invoked the command to run it:
PS> $script = {>> [threading.thread]::CurrentThread.ManagedThreadId>> [threading.thread]::CurrentThread.ManagedThreadId>> [threading.thread]::CurrentThread.ManagedThreadId>> [threading.thread]::CurrentThread.ManagedThreadId>> }>>PS> & $script16161616
If you want to run powershell interactively with a single thread, start the shell with the -STA switch. You can do this interactively:
PS> powershell -staWindows PowerShellCopyright (C) 2009 Microsoft Corporation. All rights reserved.PS> $host.runspace | select threadoptions, apartmentstateThreadOptions ApartmentState------------- --------------ReuseThread STA
As you can see, powershell will use a single-threaded apartment to execute interactive commands. This is usually the desired choice for working with WPF or WinForms, or if you want to play with system-wide mutexes:
PS> $mtx = New-Object System.Threading.Mutex($false, "CrossProcMtx")PS> $mtx.WaitOne()TruePS> $mtx.ReleaseMutex()PS> $mtx.WaitOne()True
Btw, powershell v3 (shipping with windows 8 and also available downlevel on win 7) uses -STA as the default mode for the console. The graphical powershell ISE always uses -STA, both in v2 and v3.
Using this thread as inspiration, built a simple implementation of a process locking mechanism using Mutexes in powershell:
function Wait-OnMutex{ param( [parameter(Mandatory = $true)][string] $MutexId ) try { $MutexInstance = New-Object System.Threading.Mutex -ArgumentList 'false', $MutexId while (-not $MutexInstance.WaitOne(1000)) { Start-Sleep -m 500; } return $MutexInstance } catch [System.Threading.AbandonedMutexException] { $MutexInstance = New-Object System.Threading.Mutex -ArgumentList 'false', $MutexId return Wait-OnMutex -MutexId $MutexId }}#### main method$MutexInstance = Wait-OnMutex -MutexId 'SomeMutexId12345'Write-Host "my turn"#this is where you do work inside the "lock"Read-Host $MutexInstance.ReleaseMutex()
Hope This helps somebody.