Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

I thought Powershell was MTA

23 views
Skip to first unread message

CodeSlinger

unread,
Nov 15, 2009, 2:40:09 PM11/15/09
to

I have an application that hosts Powershell and supplies the PSHost.
PSHostUserInterface and PSHostRawUserInterface interfaces and my write
routines are all reentrant and my app is MTA. When I run the below
script, that setups a timer to run a scriptblock, the scriptblock
actions are queued up and do not run until the main script thread runs
again and if it is waiting on a ManualResetEvent then they do not run
until my application signals that event and the script ends.

If instead, I uncomment and use the while ($signal -eq $false) loop
that has a WaitOne(5000) then the timers actions each time the WaitOne
times out but this is NOT the behaviour I was hoping for and is STA
behaviour not MTA.

I need to wait on this signal event which basically tells my script to
end while letting timer events run in the background. How can I do this
so that my timer actions run real time in the background and ideally can
call write-host into my application. Right now with the infinite
WaitOne(), they do not run at all!

Here is a sample script that hangs till I signal the ManualResetEvent
from my app at which point all the queued actions run with a timestamp
that shows it was not just the write-host that was hanging but the
actions themselves did not run at all.

## This example shows undesired action behaviour when the main thread
is waiting on a ManualResetEvent
## Since Powershell is MTA I should have thought this would work but
only works if
## I do something on the main script thread that runs ever once in a
while like the snippet I have commented out

$timer = New-Object System.Timers.Timer

$SendAlert =
{
$time1 = [DateTime]::Now
write-host "SendAlert fired from script block at $time1."
}

try
{
write-host "PowershellTriggerDemo was entered."

## start a timer
$timer.Interval = 5000 # every 5 seconds in ms
Register-ObjectEvent -inputObject $timer -EventName Elapsed
-SourceIdentifier Timer.Elapsed -action $SendAlert
$timer.Enabled=$true

# wait until we are told to quit while the timer goes off on a
background thread sending events
write-host "Value of CmdManQuitEvent is '$CmdManQuitEvent'"

#### The script blocks hang till this event is signaled
$CmdManQuitEvent.WaitOne()

#the below allows the timer action to run but is not my ideal
design
##$signal = $false
##while ($signal -eq $false)
##{
##$time2 = [DateTime]::Now
##$signaled = $CmdManQuitEvent.WaitOne(5000, $false) ## wait 5
seconds and wake so actions can run
##write-host "signal value is $signaled at $time2"
##}

$time3 = [DateTime]::Now
write-host "PowershellTriggerDemo ending normally at $time3."
}
catch
{
# say why we failed
$msg = $error[0].Exception.Message
write-host "PowershellTriggerDemo failed for reason '$msg'."
exit
}
finally
{
$timer.Enabled=$false
# this should run but no output is written or saved
unRegister-Event -SourceIdentifier Timer.Elapsed
write-host "Finally ran."
}


--
CodeSlinger

Oisin (x0n) Grehan [MVP]

unread,
Nov 18, 2009, 8:10:16 PM11/18/09
to

MTA does not equal multithreaded. At any one time, powershell has one
active thread in the MTA pool servicing input from the console;
blocking this thread will most likely not allow it to service events.
If you wish to wait on events and/or jobs (which service events),
investigate Wait-Job and Wait-Event. PowerShell has its own finely
tuned infrastructure to work with asynchronous eventing; just because
waithandles are available to use (purely incidentally through access
to the .net framework), it doesn't mean you can impose your own
intepretation on their framework.

-Oisin

0 new messages