You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

停止PowerShell时,.NET方法的赋值操作是否具备原子性?

背景信息

原子性的工作定义

针对本问题,适用以下“原子性”定义:

给定运行空间中执行的一条语句:
a. 包含一个调用.NET方法生成新对象的表达式;
b. 引用了该语句作用域内可访问的PowerShell变量;
c. 该语句是将(a)中.NET方法返回的对象赋值给(b)中的PowerShell变量;
d. 若运行空间未被停止,该语句及赋值操作可无错误或异常执行完成;

当且仅当对于所有可能的组合:
e. 触发运行空间停止的时间点;
f. 符合C#或.NET标准规范的.NET方法有效实现;

满足以下任一情况时,该语句具备原子性:
g. .NET方法未开始执行;
h. .NET方法完整执行完毕,且返回的对象被赋值给目标变量。

另有补充定义可提升清晰度:

……假设右侧表达式已执行完成,且赋值给目标变量未违反类型约束,Stop-Job是否会阻碍赋值操作?

不具备原子性的赋值表达式

构造一个对象已创建但赋值未完成的语句十分简单,如下例(看似有些反常):

$fs =
    @([System.IO.StreamWriter]::new($filePath)
      Start-Sleep 1)

此场景下,作业可能在第一个StreamWriter未被释放时就被停止,后续第二个new()会执行失败并抛出错误:

Exception calling ".ctor" with "1" argument(s): "The process cannot access the file 'C:\Users\User\AppData\Local\Temp\tmpzc3tf0.tmp' because it is being used by another process."

但其中显眼的Start-Sleep 1可替换为任何合法的实用操作。另一个易受此问题影响的场景是构造函数被封装在New-StreamWriter这类高级函数中。引入高级函数是否会导致其调用的.NET方法赋值失去原子性?

测试结果

我准备了以下测试,用于检测不同表达式的赋值是否不具备原子性。但即使赋值实际不具备原子性,测试也可能因时机巧合而通过。因此该测试只能发现问题,无法证明无问题。

测试输出如下:

result assignment                                         use_again_error
------ ----------                                         ---------------
-      $fs = [System.IO.StreamWriter]::new($filePath)
        $c.Set()
-      $fs = New-Object System.IO.StreamWriter $filePath
        $c.Set()
❌      $fs =                                              Exception calling ".ctor" with "1" argument(s): "The
           @([System.IO.StreamWriter]::new($filePath)     process cannot access the file
             $c.Set()                                     'C:\Users\User1\AppData\Local\Temp\tmpgm0d0q.tmp' because
             Start-Sleep 1)                               it is being used by another process."
-      $fs = New-StreamWriter $filePath

测试代码

{$fs = [System.IO.StreamWriter]::new($filePath)
 $c.Set()                                         } ,
{$fs = New-Object System.IO.StreamWriter $filePath
 $c.Set()                                         } ,
{$fs =
    @([System.IO.StreamWriter]::new($filePath)
      $c.Set()
      Start-Sleep 1)                              } ,
{$fs = New-StreamWriter $filePath} |
ForEach-Object {
    $assignment = $_
    $filePath = [system.io.path]::GetTempFileName()
    $c = [System.Threading.ManualResetEventSlim]::new() # 标记构造函数已执行完成
    $job =
        Start-ThreadJob `
            -ArgumentList $filePath,$assignment,$c `
            -ScriptBlock {
                param($filePath,$assignment,$c)
                begin {
                    function New-StreamWriter {
                        param($filePath)
                        [System.IO.StreamWriter]::new($filePath)
                        $c.Set()
                    }
                }
                end {
                    . ($assignment.Ast.GetScriptBlock())
                }
                clean {
                    ${fs}?.Dispose()
                }
            }
    $c.Wait() | Out-Null
    $assignment_error =
        @(
            $job.Error
            try {
                $job | Receive-Job -ea Stop
            }
            catch {
                $_
            }
        ) |
            Select-Object -Unique

    $use_again_error  = $(try { $fs2 = [System.IO.StreamWriter]::new($filePath)} catch {$_})
    [pscustomobject]@{
        result           = $(if($assignment_error) {'⚠️'} else {if($use_again_error) {'❌'} else {''}})
        assignment       = $assignment
        assignment_error = $assignment_error
        use_again_error  = $use_again_error
    }
    ${fs2}?.Dispose()
} |
Format-Table `
    -Wrap `
    -Property @(
        @{ Name = 'result';Expression = 'result'; Width = 'result'.Length }
        @{ Name = 'assignment';Expression = 'assignment'; Width = 50 }
        @{ Name = 'use_again_error';Expression = 'use_again_error'; Width = 60 }
    )

内容的提问来源于stack exchange,提问作者alx9r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 16:26:01