在 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 是否在后台执行一些奇怪的线程恶作剧,或者我完全忘记了互斥体是如何工作的?
While debugging an application that uses Semaphores for cross-process synchronization, I stumbled upon the idea of using PowerShell to take the place of the "other" process. Doing something like this in PowerShell works fine:
// 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()
And I can call WaitOne()
and Release()
repeatedly on that same instance of a Semaphore, as often as I need to.
But when I try to do the same thing with a Mutex, PowerShell keeps claiming that the mutex was abandoned:
[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
The error seems to happen any time I call WaitOne()
after having acquired the mutex once before, either a previous WaitOne
call or asking for it to be initially owned in the constructor:
[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
Is Powershell doing some wierd thread shenanigans in the background or am I just completely forgetting how Mutexes work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
默认情况下,powershell v2.0(在控制台,而不是图形 ISE)使用 MTA 线程池。这意味着每个交互行都在不同的线程上执行:
但是,非交互脚本将在单个线程下运行,也就是说,调用命令来运行它的线程:
如果您想运行 powershell与单线程交互,使用 -STA 开关启动 shell。您可以交互式地执行此操作:
如您所见,powershell 将使用单线程单元来执行交互式命令。这通常是使用 WPF 或 WinForms 的理想选择,或者如果您想使用系统范围的互斥体:
顺便说一句,powershell v3(随 Windows 8 一起提供,也可在 win 7 上使用)使用 -STA 作为默认模式控制台。图形 Powershell ISE 始终使用 -STA,无论是在 v2 还是 v3 中。
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:
However, a non-interactive script will run under a single thread, that is to say, the thread that invoked the command to run it:
If you want to run powershell interactively with a single thread, start the shell with the -STA switch. You can do this interactively:
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:
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.
以此线程为灵感,在 powershell 中使用互斥体构建了进程锁定机制的简单实现:
希望这对某人有帮助。
Using this thread as inspiration, built a simple implementation of a process locking mechanism using Mutexes in powershell:
Hope This helps somebody.