2011-10-05 14 views
7

交互式使用互斥(等人)中是在調試使用信號量爲跨進程同步的應用程序,我偶然發現使用PowerShell來採取「其他」過程的地方的想法。做這樣的事情在PowerShell中正常工作:在Powershell的

// In C# application: 
var sem = new Semaphore(0, 1, "CrossProcSem"); 
sem.WaitOne(); 

# In PowerShell session: 
[1] C:\Projects $ $sem = New-Object System.Threading.Semaphore(0, 1, "CrossProcSem") 
[2] C:\Projects $ $sem.Release() 

而且我可以打電話WaitOne()Release()反覆基於信號的同一實例,經常因爲我需要。

但是,當我試圖做同樣的事情用一個互斥量,PowerShell會聲稱互斥體被遺棄:

[1] C:\Projects $ $mtx = New-Object System.Threading.Mutex($false, "CrossProcMtx") 
[2] C:\Projects $ $mtx.WaitOne() 
True 
[3] C:\Projects $ $mtx.ReleaseMutex() 
[4] C:\Projects $ $mtx.WaitOne() 
Exception calling "WaitOne" with "0" argument(s): "The wait completed due to an abandoned mutex." 
At line:1 char:13 
+ $mtx.WaitOne <<<<() 
    + CategoryInfo   : NotSpecified: (:) [], ParentContainsErrorRecordException 
    + FullyQualifiedErrorId : DotNetMethodException 

的錯誤似乎之前在已經獲取互斥一旦發生任何時間,我打電話WaitOne() ,無論是以前WaitOne電話或要求它在構造函數中最初擁有:

[5] C:\Projects $ $mtx2 = New-Object System.Threading.Mutex($true) 
[6] C:\Projects $ $mtx2.WaitOne() 
Exception calling "WaitOne" with "0" argument(s): "The wait completed due to an abandoned mutex." 
At line:1 char:14 
+ $mtx2.WaitOne <<<<() 
    + CategoryInfo   : NotSpecified: (:) [], ParentContainsErrorRecordException 
    + FullyQualifiedErrorId : DotNetMethodException 

[7] C:\Projects $ $mtx3 = New-Object System.Threading.Mutex 
[8] C:\Projects $ $mtx3.WaitOne() 
True 
[9] C:\Projects $ $mtx3.WaitOne() 
Exception calling "WaitOne" with "0" argument(s): "The wait completed due to an abandoned mutex." 
At line:1 char:14 
+ $mtx3.WaitOne <<<<() 
    + CategoryInfo   : NotSpecified: (:) [], ParentContainsErrorRecordException 
    + FullyQualifiedErrorId : DotNetMethodException 

是PowerShell的做在後臺的一些奇怪的線程有心計或者我只是渾然如何互斥w ^掃?

回答

25

默認情況下,2.0的powershell(在控制檯,而不是在圖形ISE)使用MTA線程池。這意味着,每個交互線在不同的線程中執行:

PS> [threading.thread]::CurrentThread.ManagedThreadId 
13 
PS> [threading.thread]::CurrentThread.ManagedThreadId 
10 
PS> [threading.thread]::CurrentThread.ManagedThreadId 
8 
PS> [threading.thread]::CurrentThread.ManagedThreadId 
4 

然而,非交互式腳本將單線程下運行,也就是說,調用該命令的線程來運行它:

PS> $script = { 
>> [threading.thread]::CurrentThread.ManagedThreadId 
>> [threading.thread]::CurrentThread.ManagedThreadId 
>> [threading.thread]::CurrentThread.ManagedThreadId 
>> [threading.thread]::CurrentThread.ManagedThreadId 
>> } 
>> 
PS> & $script 
16 
16 
16 
16 

如果你想用一個單獨的線程交互運行PowerShell中,先從-STA開關外殼。您可以交互式地執行此操作:

PS> powershell -sta 
Windows PowerShell 
Copyright (C) 2009 Microsoft Corporation. All rights reserved. 

PS> $host.runspace | select threadoptions, apartmentstate 
ThreadOptions  ApartmentState 
-------------  -------------- 
ReuseThread     STA 

正如您所看到的,powershell將使用單線程套件來執行交互式命令。這通常是用WPF或WinForms的工作所需要的選項,或者如果你想全系統互斥玩:

PS> $mtx = New-Object System.Threading.Mutex($false, "CrossProcMtx") 
PS> $mtx.WaitOne() 
True 
PS> $mtx.ReleaseMutex() 
PS> $mtx.WaitOne() 
True 

順便說一句,PowerShell的V3用途(與Windows 8和Win 7的也可下層出貨) -STA作爲控制檯的默認模式。圖形PowerShell ISE在v2和v3中始終使用-STA。

+0

+1 - 我談的是V3.0發表評論,因爲OP的榜樣爲我工作在3.0 CTP,我意識到V3.0(控制檯)爲STA默認。然後看到你做到了這一點:) – manojlds

+0

+1清除樣品。明確的答案。 –

+0

無論Powershell實例的MTA/STA如何,您都不能只提供一個「全局」互斥體名稱? – Signal15

1

使用這個線程爲靈感,建立了一個簡單的實現在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() 

希望這可以幫助別人。