Interactively using Mutexes (et al) in Powershell Interactively using Mutexes (et al) in Powershell multithreading multithreading

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.