Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weird error running Invoke-Parallel #62

Open
MarkKharitonov opened this issue May 20, 2019 · 0 comments
Open

Weird error running Invoke-Parallel #62

MarkKharitonov opened this issue May 20, 2019 · 0 comments

Comments

@MarkKharitonov
Copy link

Please, observe the following script:

param([switch]$Cleanup, [Switch]$MockMutex, $N = 1)

function Cleanup()
{
    1..$N | ForEach-Object {
        Unregister-PSRepository "r$_" -ErrorAction SilentlyContinue
    }
    Remove-Item $WorkDir -ErrorAction SilentlyContinue -Recurse
}

$WorkDir = "$env:TEMP\fb22c60e-a0c5-48b3-953a-0b580c6a2f5e"
if ($Cleanup)
{
    Cleanup
}
else
{
    if ($MockMutex)
    {
        class MutexMock
        {
            WaitOne() { }
            ReleaseMutex() { }
        }
        $mtx = [MutexMock]::New()
    }
    else
    {
        $mtx = [Threading.Mutex]::New($false)
    }

    1..$N | Invoke-Parallel {
        $RepositoryName = "r$_"
        $WorkDir = $Using:WorkDir

        $null = mkdir "$WorkDir\$RepositoryName" -Force -ErrorAction SilentlyContinue

        $null = $parameter.WaitOne()
        try
        {
            if (!(Get-PSRepository -Name $RepositoryName -ErrorAction SilentlyContinue))
            {
                Write-Host "[$([AppDomain]::GetCurrentThreadId())] BEGIN[$RepositoryName]"
                Register-PSRepository $RepositoryName `
                    -SourceLocation "$WorkDir\$RepositoryName" `
                    -PublishLocation "$WorkDir\$RepositoryName" `
                    -InstallationPolicy Trusted
                Write-Host "[$([AppDomain]::GetCurrentThreadId())]      [$RepositoryName]END"
            }
        }
        finally
        {
            $parameter.ReleaseMutex()
        }
    } -Parameter $mtx
    Get-PSRepository | Where-Object { $_.Name.StartsWith('r') }
    Cleanup
}

It just tries to run Register-PSRepository in parallel the given number of times. The default is to use a mutex to actually serialize the calls to the functions Get-PSRepository and Register-PSRepository (thus killing the parallelism, of course, but this is a different story). Passing -MockMutex switch replaces a real mutex object with a mock.

Strange things happen when calling with the mock and N greater than 1:

PS C:\> .\1.ps1 -MockMutex -N 2
Get-RunspaceData : A parameter cannot be found that matches parameter name 'Provider'.
At C:\misc\Invoke-Parallel.ps1:591 char:13
+             Get-RunspaceData -wait
+             ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Write-Error], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Get-RunspaceData
 
[37616] BEGIN[r1]
[37616]      [r1]END

Name                      InstallationPolicy   SourceLocation
----                      ------------------   --------------
r1                        Trusted              C:\Users\MKHARI~1\AppData\Local\Temp\fb22c60e-a0c5-48b3-953a-0b580c6a2f5e\r1


PS C:\>

All works fine when N = 1 or when called with a real mutex object.

The only explanation that I see is that the Get/Register-PSRepository functions are not multi-thread safe and calling them in parallel screws things up in such a way that it affects Invoke-Parallel somehow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant