Интерактивно используя Mutexes (и др.) В Powershell - PullRequest
8 голосов
/ 05 октября 2011

При отладке приложения, использующего семафоры для межпроцессной синхронизации, я наткнулся на идею использования 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() в одном и том же экземпляре семафора, так часто, как мне нужно.

Но когда я пытаюсь сделать то же самое с Mutex, 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 выполняет какие-то странные махинации в фоновом режиме или я просто полностью забыл, как работают мьютексы?

Ответы [ 2 ]

26 голосов
/ 05 октября 2011

По умолчанию powershell v2.0 (на консоли, а не на графическом 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 в качестве режима по умолчанию для консоли.Графический ISE PowerShell всегда использует -STA, как в v2, так и в v3.

1 голос
/ 01 июля 2016

Используя этот поток для вдохновения, мы создали простую реализацию механизма блокировки процессов с использованием Mutexes в 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()

Надеюсь, это кому-нибудь поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...