You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add 2 parameters to Start-ThreadJob: timeout seconds, priority #26
HANG The regularity of unpredictable execution time
Regular expression for a long time and unpredictable time.
Code executed remotely.
memory leaks
cpu 100%
like:
golang : “context.WithTimeout”
python : timeout* in threading lib
It is better to add a Boolean type of parameter : -AutoRemoveJob
whether to automatically remove threadjob after timeout,
parameter likes “receive-job -AutoRemoveJob”
In this way, users can only consider new thread and put ps1 script code.
both "ForEach-Object -Parallel" and "Start-ThreadJob" without timeout, This has seriously affected my development of "kasini3000" at present.
Powershell community do a "engine",i do a "car". the car is kasini3000 and k4t .
I love powershell. I want to give my opinion to the engine.
I hope the engine factory can transform a better engine.
I think timeoutseconds can make the ps1 script in the thread more robust.
I hope powershell will become stronger and stronger.
How does a timeout solve this? All you end up with is a section the task run and an indeterminate end state.
HANG
If the thread is hung and unresponsive, you won't be able to cancel it with a cooperative cancellation mechanism (eg cancellation is an unwind performed in the thread). Preemptive termination leaves the process in an indeterminate state.
The regularity of unpredictable execution time.
PowerShell is not a RTOS
Code executed remotely.
Is the expectation that cancelling a local thread will also propagate to cancel remote threads, processes or any child local processes? What mechanism should be used to terminate a remote process?
memory leaks
How does a timeouts solve memory leaks? If a thread is leaking memory and you stop it, it has still leaked memory, the memory won't be recovered. If the memory is recovered by the thread termination then it is not actually a leak, it is just memory usage.
cpu 100%
100% CPU is not an issue if it is performing the required jobs. Cancelling a thread because you have high CPU just means you aren't performing the jobs you expected it to perform.
kasini3000 Are you able to implement timed thread cancellation in your own code?
For example when you create a thread also create a CancellationToken and call CancellationTokenSource.CancelAfter to set your timeout. Then each thread has a cancellation token, use a static ThreadLocal<> to associate the thread token with each thread when they start.
Where ever you have a loop, then also check the state of the CancellationToken associated with the current thread and if cancelled throw an exception. Likewise anywhere that you Thread.Sleep(timeout), do cancellationToken.WaitHandle.WaitOne(timeout) and again throw an exception if the cancellation has occurred.
This could be implemented in a small C# class that you use in your PowerShell project.
timeoutseconds can make the ps1 script in the thread more robust.
The example you share is very important to the powershell community and USERS !!!
thanks rhubarb-geek-nz !!!
I hope ANYONE can provide PR as soon as possible to realize this function
The more I look at PowerShell threads the more I think it is better to forget about them actually being threads. I may be completely wrong about this but PowerShell threads are completely isolated from other threads, this is unlike a traditional threading system where threads share memory. Here it appears that threads use their own runspace and are isolated from others. From my tests, even $Global are not global, they seem effectively visible only with that thread/runspace.
So within a thread script block you might as well just pass the token around as a variable or put it in $Global.
This does mean you can use exactly the same mechanism for jobs that run in other processes or on other machines.
Rather than think about it as job cancellation or job timeout, think of it in terms of what are the conditions under which my job will terminate. The token is then just part of the calculation.
That said, if they are threads running in the same process you might be able to pass a cancellation token created in the main thread or any other thread onto another thread via argument list into the parameters of a script block. This would not work for jobs in other process or remote jobs.
stevenebutler I saw you adding a cancellation token to IWR. Do you have time to address this issue?
I don't really know much about this side of PowerShell so I don't think I can help here. If I read the issue correctly (and I may not) you are looking for something to cancel jobs that are running after a timeout.
If that's the case I don't think cancellation tokens are going to help you because they rely on the code being cancelled being co-operative in that it must periodically check for cancellation. If you're stuck inside third party code that does not use/check a cancellation token then it will not take any notice of the cancellation of the token and will continue to process until it finishes. The fix I applied was to make the code base in IWR (which we control) more co-operative by checking the cancellation token in places where it was not.
sounds good.
1 Add an attribute to the job: endtime. The value is the current time plus [timespan] 'sometime'
2 Then regularly reduce the inspection and cancel it.
If you're stuck inside third party code that does not use/check a cancellation token then it will not take any notice of the cancellation of the token and will continue to process until it finishes.
Can the job be placed in a subfunction that enforces the use of a cancel token?
There seems to be a saying that forces the insertion of a sleep some millisecond in the powershell job code. Canceling the token will be executed.
The only way I know of to deal with an uncancellable job is to do one of the following
terminate the process (if running out of process);
terminate the thread running it (very unreliable and causes major issues with stability and probably not even possible if it's a C# Task based job); or
run it in a background task and just leave it running but give up waiting for the outcome once it goes past its timeout. This is obviously not ideal because the job will continue to consume resources but you no longer care about the outcome.
If you're trying to cancel arbitrary code, the safest way to do it is to run it in a separate process and terminate that once the timeout is reached. You should be able to do this already using start-job and related cmdlets.
If you're trying to cancel arbitrary code, the safest way to do it is to run it in a separate process and terminate that once the timeout is reached
Even if you don't want to help PR, don't say that.
IWR's timeout does not start a new process and can also terminate threads.
no new thread in IWR ?i don‘t know.
The thread must be able to be terminated. this issue only want adding a timeout-- If a thread may never be terminated, who dares to use it?
golang : “context.WithTimeout”
python : timeout* in threading lib
The process can hang, so someone invented the kill command.
Your computer can hang, so someone invented the reset key.
Next, go to glibc and find a way to stop the thread.
I eat every day, cook often, and it's a common thing to remove rotten leaves from a vegetable. (I allow the loss of some good leaves, just like allowing thread termination to allow a small amount of data loss.)
Well, leave foolishness and find a way out.
The process can hang, so someone invented the kill command.
First computers could only run on program at a time. Later computers supported processes to varying levels of degree to allow multiple programs to run on the expensive hardware.
If you do not have pre-emptive multi-tasking and memory protection then all other processes are at risk from the worst program. Compare Windows 3.1 to OS/2, or Windows 95 to Windows NT, the system with process and kernel isolation and strong memory protection provides the most reliable system. Consider Windows 3.1, Windows 95 and any Macintosh System below 10 were absolutely terrible in terms of process isolation. Programming errors could cause memory corruption in any process.
The game changer in reliability of systems was the introduction of virtual memory, preemptive multitasking and memory protection. So as you mentioned the kill command. The killing of processes is incredibly efficient because there is no cleanup of the process to be done. All that happens is the open file handles are closed, the memory for the entire process marked as available and a signal raised to indicate the process is finished.
Now if you look at how UNIX shells operate, they don't need to use threads to achieve efficient pipelines and parallelism. They work using fork and copy-on-write, so rather than creating a thread the entire process is cloned and two versions of the same program run using the same memory but with memory protection between them. Only on memory-write is new memory allocated to manage the difference in memory state on a page by page basis. Either could terminate and the other would be unaffected, except for the SIGCHLD signal going to the parent.
Threading in a single process is much harder. It is hard to write robust preemptive multithreading code. It is hard when you write the entire program, it is even harder when you then include 3rd party code into your process which does not abide by the rules.
So I will keep mentioning why TerminateThread is so bad, it completely trashes your ability to maintain a consistent memory image. Let's ask Raymond what happens when a thread is terminated and it releases a mutex. Spoiler, you’re in big trouble.
The TerminateThread does not care if you are running PowerShell script, C# code or native C or C++ code. It will terminate it all without giving the code the opportunity to either protect itself or clean up.
If you want to put this in perspective, this is an ideal way to corrupt an SQLite database. The updates to the database were taking too long so terminate the thread! You risk corrupting the structures used to manage the data and transaction control.
In the POSIX world pthread_cancel is used terminate a thread. The way that code protects itself from this is using pthread_setcancelstate to protect critical sections. In this case the value of PTHREAD_CANCEL_DISABLE will prevent the cancellation from occurring. This is again a cooperative model, pthread_cancel simply marks that a thread should terminate but requires the thread to perform the termination itself by exiting.
It is generally a bad pattern to kill a thread abruptly, in Python, and in any language.
Exactly the same story.
A good usage pattern of this code is to have the thread catch a specific exception and perform the cleanup. That way, you can interrupt a task and still have proper cleanup.
Exactly what we are saying with cooperative threads.
Another approach that you can do yourself is to create a cancellation token to define the time a thread should take and then use Register-ObjectEvent to register a handler to terminate the job.
You need an actual dotnet class with an event that can be used by Register-ObjectEvent, this also registers an Action delegate with the cancellation token.
Add-Type -Language CSharp @"
using System;
using System.Threading;
namespace RhubarbGeekNz
{
public class CancellationEvent : IDisposable
{
public event Action Cancelled;
public void Dispose() => Token.Dispose();
private readonly IDisposable Token;
public CancellationEvent(CancellationToken ct)
{
Token = ct.Register(()=>Cancelled());
}
}
}
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 CancelExample ThreadJob NotStarted False PowerShell …
1 CancelExample ThreadJob Completed True PowerShell …
begin job
finally job
Invoke-CommandWithCancellationToken:
Line |
3 | Invoke-CommandWithCancellationToken -ScriptBlock {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| The operation was canceled.
Multiple threads can share the same cancellation token, so create a single cancellation token to be cancelled after 5 minutes and start twenty threads using the same cancellation token, then all will be cancelled in 5 minutes.
With the PSGallery module I published you can do that right now.
Unfortunately PowerShell is not really task/async/await aware. Within a cmdlet it relies on thread local storage for context.
I would suggest that within a cmdlet you create a child thread (not with ThreadJob) run your async tasks from that and wait on an event in your cmdlet that you indicate all your async tasks are finished and then return.
It isn't safe to call PSCmdlet.WriteObject for instance from within a task that has lost all connection with the thread that PowerShell called your cmdlet's methods on.
Because the lack of support from Invoke-WebRequest for HttpRequest streaming and WebSockets. I am forced to use the dotnet Types & instances.
I can query and execute commands to the Kubernetes API without any 3th party compiled assemblies from the pwsh 7.4
without spawning any child-processes for 70mb memory each.
The issue persist that currently the pwsh Runspace/Host does not provide any native Signal/WaitHandle/Callback to abort an operation.
To call sync-over-async method in a STA environment will always produce a lock, but it does not mean that the inside async-method can not be cancelled with over a CancellationToken
Something like this would already useful in many await/async situations.
Signals don't really fit with my idea of PowerShell, they are process owned, where as I see the point of PowerShell is to write small reusable scripts, modules, functions and cmdlets that do not own the process and are then assembled for some higher purpose to solve a problem.
My theory is that the PowerShell host itself should have the signal handler and the root console interactive session or script gets a cancellation token that will be tripped by that.
Good luck with your solution, sounds fun.
I wrote an ASP web server that uses HttpContext.RequestAborted to call PowerShell.StopAsync when a response was no longer worthwhile as the client had disconnected.
Activity
rhubarb-geek-nz commentedon Jan 29, 2023
How does a timeout solve this? All you end up with is a section the task run and an indeterminate end state.
If the thread is hung and unresponsive, you won't be able to cancel it with a cooperative cancellation mechanism (eg cancellation is an unwind performed in the thread). Preemptive termination leaves the process in an indeterminate state.
PowerShell is not a RTOS
Is the expectation that cancelling a local thread will also propagate to cancel remote threads, processes or any child local processes? What mechanism should be used to terminate a remote process?
How does a timeouts solve memory leaks? If a thread is leaking memory and you stop it, it has still leaked memory, the memory won't be recovered. If the memory is recovered by the thread termination then it is not actually a leak, it is just memory usage.
100% CPU is not an issue if it is performing the required jobs. Cancelling a thread because you have high CPU just means you aren't performing the jobs you expected it to perform.
rhubarb-geek-nz commentedon Jan 29, 2023
kasini3000 Are you able to implement timed thread cancellation in your own code?
For example when you create a thread also create a CancellationToken and call CancellationTokenSource.CancelAfter to set your timeout. Then each thread has a cancellation token, use a static ThreadLocal<> to associate the thread token with each thread when they start.
Where ever you have a loop, then also check the state of the CancellationToken associated with the current thread and if cancelled throw an exception. Likewise anywhere that you Thread.Sleep(timeout), do cancellationToken.WaitHandle.WaitOne(timeout) and again throw an exception if the cancellation has occurred.
This could be implemented in a small C# class that you use in your PowerShell project.
rhubarb-geek-nz commentedon Jan 29, 2023
Likewise, in the same module you can do
To adjust the priority.
rhubarb-geek-nz commentedon Jan 29, 2023
Suggest use existing ThreadPriority enum
rhubarb-geek-nz commentedon Jan 30, 2023
This is a pattern you can use now and also on original non-core PowerShell.exe
kasini3000 commentedon Feb 2, 2023
timeoutseconds can make the ps1 script in the thread more robust.
The example you share is very important to the powershell community and USERS !!!
thanks rhubarb-geek-nz !!!
I hope ANYONE can provide PR as soon as possible to realize this function
kborowinski commentedon Feb 21, 2023
rhubarb-geek-nz Could you show a small example how to use
ThreadLocalwith cancelation token inside of theStart-ThreadJobscriptblock?rhubarb-geek-nz commentedon Feb 21, 2023
The more I look at PowerShell threads the more I think it is better to forget about them actually being threads. I may be completely wrong about this but PowerShell threads are completely isolated from other threads, this is unlike a traditional threading system where threads share memory. Here it appears that threads use their own runspace and are isolated from others. From my tests, even $Global are not global, they seem effectively visible only with that thread/runspace.
So within a thread script block you might as well just pass the token around as a variable or put it in $Global.
This does mean you can use exactly the same mechanism for jobs that run in other processes or on other machines.
Rather than think about it as job cancellation or job timeout, think of it in terms of what are the conditions under which my job will terminate. The token is then just part of the calculation.
rhubarb-geek-nz commentedon Feb 21, 2023
That said, if they are threads running in the same process you might be able to pass a cancellation token created in the main thread or any other thread onto another thread via argument list into the parameters of a script block. This would not work for jobs in other process or remote jobs.
kasini3000 commentedon Apr 4, 2023
stevenebutler
I saw you adding a cancellation token to IWR. Do you have time to address this issue?
kasini3000 commentedon Apr 12, 2023
news:asp.net8 pr3 add timeout for per request
https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-preview-3/
You can set request timeouts for individual endpoints, controllers, or dynamically per request.
To apply request timeouts, first add the request timeout services:
builder.Services.AddRequestTimeouts();
You can then apply request timeouts using middleware by calling :UseRequestTimeouts()
stevenebutler commentedon Apr 16, 2023
I don't really know much about this side of PowerShell so I don't think I can help here. If I read the issue correctly (and I may not) you are looking for something to cancel jobs that are running after a timeout.
If that's the case I don't think cancellation tokens are going to help you because they rely on the code being cancelled being co-operative in that it must periodically check for cancellation. If you're stuck inside third party code that does not use/check a cancellation token then it will not take any notice of the cancellation of the token and will continue to process until it finishes. The fix I applied was to make the code base in IWR (which we control) more co-operative by checking the cancellation token in places where it was not.
kasini3000 commentedon Apr 17, 2023
sounds good.
1 Add an attribute to the job: endtime. The value is the current time plus [timespan] 'sometime'
2 Then regularly reduce the inspection and cancel it.
Can the job be placed in a subfunction that enforces the use of a cancel token?
There seems to be a saying that forces the insertion of a sleep some millisecond in the powershell job code. Canceling the token will be executed.
stevenebutler commentedon Apr 19, 2023
The only way I know of to deal with an uncancellable job is to do one of the following
If you're trying to cancel arbitrary code, the safest way to do it is to run it in a separate process and terminate that once the timeout is reached. You should be able to do this already using start-job and related cmdlets.
kasini3000 commentedon Apr 19, 2023
Even if you don't want to help PR, don't say that.
IWR's timeout does not start a new process and can also terminate threads.
no new thread in IWR ?i don‘t know.
The thread must be able to be terminated. this issue only want adding a timeout-- If a thread may never be terminated, who dares to use it?
golang : “context.WithTimeout”
python : timeout* in threading lib
this issue force me to use Python or Golang
13 remaining items
kasini3000 commentedon Apr 28, 2023
The process can hang, so someone invented the kill command.
Your computer can hang, so someone invented the reset key.
Next, go to glibc and find a way to stop the thread.
I eat every day, cook often, and it's a common thing to remove rotten leaves from a vegetable. (I allow the loss of some good leaves, just like allowing thread termination to allow a small amount of data loss.)
Well, leave foolishness and find a way out.
rhubarb-geek-nz commentedon Apr 28, 2023
First computers could only run on program at a time. Later computers supported processes to varying levels of degree to allow multiple programs to run on the expensive hardware.
If you do not have pre-emptive multi-tasking and memory protection then all other processes are at risk from the worst program. Compare Windows 3.1 to OS/2, or Windows 95 to Windows NT, the system with process and kernel isolation and strong memory protection provides the most reliable system. Consider Windows 3.1, Windows 95 and any Macintosh System below 10 were absolutely terrible in terms of process isolation. Programming errors could cause memory corruption in any process.
The game changer in reliability of systems was the introduction of virtual memory, preemptive multitasking and memory protection. So as you mentioned the
killcommand. The killing of processes is incredibly efficient because there is no cleanup of the process to be done. All that happens is the open file handles are closed, the memory for the entire process marked as available and a signal raised to indicate the process is finished.Now if you look at how UNIX shells operate, they don't need to use threads to achieve efficient pipelines and parallelism. They work using fork and copy-on-write, so rather than creating a thread the entire process is cloned and two versions of the same program run using the same memory but with memory protection between them. Only on memory-write is new memory allocated to manage the difference in memory state on a page by page basis. Either could terminate and the other would be unaffected, except for the SIGCHLD signal going to the parent.
Threading in a single process is much harder. It is hard to write robust preemptive multithreading code. It is hard when you write the entire program, it is even harder when you then include 3rd party code into your process which does not abide by the rules.
So I will keep mentioning why
TerminateThreadis so bad, it completely trashes your ability to maintain a consistent memory image. Let's ask Raymond what happens when a thread is terminated and it releases a mutex. Spoiler, you’re in big trouble.The TerminateThread does not care if you are running PowerShell script, C# code or native C or C++ code. It will terminate it all without giving the code the opportunity to either protect itself or clean up.
If you want to put this in perspective, this is an ideal way to corrupt an SQLite database. The updates to the database were taking too long so terminate the thread! You risk corrupting the structures used to manage the data and transaction control.
In the POSIX world
pthread_cancelis used terminate a thread. The way that code protects itself from this is usingpthread_setcancelstateto protect critical sections. In this case the value ofPTHREAD_CANCEL_DISABLEwill prevent the cancellation from occurring. This is again a cooperative model,pthread_cancelsimply marks that a thread should terminate but requires the thread to perform the termination itself by exiting.rhubarb-geek-nz commentedon Apr 29, 2023
PowerShell is often compared to python, both high level scripting languages. Let's see what they have to say about it...
https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread
Exactly the same story.
Exactly what we are saying with cooperative threads.
rhubarb-geek-nz commentedon May 12, 2023
Another approach that you can do yourself is to create a cancellation token to define the time a thread should take and then use Register-ObjectEvent to register a handler to terminate the job.
You need an actual dotnet class with an event that can be used by Register-ObjectEvent, this also registers an Action delegate with the cancellation token.
Create your thread as normal
Now set up the cancellation token to expire after 5000 milliseconds
Set up the objects to connect the cancellation token to generate a PowerShell event for that job
Now wait for the event and stop the associated job, the job identifier comes from the event
MessageData. TheSenderis the$cancellationEvent.And get the result of the terminated job
So those are the building blocks, it shows you can manage both remote and local jobs with your own timeout mechanism.
rhubarb-geek-nz commentedon May 12, 2023
You could implement the stop-job within the action of the object event.
I find you still need Wait-Event to be running to process the event queue. The New-Event is to unblock the waiting Wait-Event.
rhubarb-geek-nz commentedon May 13, 2023
See github and PSGallery for module to create the event registration
rhubarb-geek-nz commentedon May 19, 2023
Have updated the above package to let you cancel a
ScriptBlockrhubarb-geek-nz commentedon May 21, 2023
kasini3000 example of using a cancellation token to implement a thread timeout
Result is
Multiple threads can share the same cancellation token, so create a single cancellation token to be cancelled after 5 minutes and start twenty threads using the same cancellation token, then all will be cancelled in 5 minutes.
With the PSGallery module I published you can do that right now.
rhubarb-geek-nz commentedon May 21, 2023
Golang's approach is still cooperative.
Go will still panic and stop the process if things are not in order.
https://forum.golangbridge.org/t/why-does-go-terminate-the-whole-process-if-one-goroutine-paincs/27122
rhubarb-geek-nz commentedon May 21, 2023
This example creates one cancellation token with cancels after 5000ms. The same token is passed to 6 threads, they are all cancelled at the same time
Output is
Zetanova commentedon Apr 2, 2024
Is there any good solution to call a .net async method with cancellation?
I want to be able to cancel ctrl+c a
StreamReader.ReadLineAsyncNothing seams to work, beside to kill the pwsh instance.
The reader will be later inside a
Start-ThreadJob,but it is very inconvenient not to create/debug in the main runspace.
rhubarb-geek-nz commentedon Apr 3, 2024
Unfortunately PowerShell is not really task/async/await aware. Within a cmdlet it relies on thread local storage for context.
I would suggest that within a cmdlet you create a child thread (not with ThreadJob) run your async tasks from that and wait on an event in your cmdlet that you indicate all your async tasks are finished and then return.
It isn't safe to call PSCmdlet.WriteObject for instance from within a task that has lost all connection with the thread that PowerShell called your cmdlet's methods on.
An alternative would be to use rhubarb-geek-nz.CancellationTokenEvent/ and use Invoke-CommandWithCancellationToken to call Invoke-WebRequest, that would keep all your code in PowerShell.
Zetanova commentedon Apr 4, 2024
rhubarb-geek-nz thx, for your help and input.
Because the lack of support from Invoke-WebRequest for HttpRequest streaming and WebSockets. I am forced to use the dotnet Types & instances.
I can query and execute commands to the Kubernetes API without any 3th party compiled assemblies from the pwsh 7.4
without spawning any child-processes for 70mb memory each.
The issue persist that currently the pwsh Runspace/Host does not provide any native Signal/WaitHandle/Callback to abort an operation.
To call sync-over-async method in a STA environment will always produce a lock, but it does not mean that the inside async-method can not be cancelled with over a
CancellationTokenSomething like this would already useful in many await/async situations.
or something like the new
ForEach-Object -Parallelwhere$MyCancellationwould be a well-known variable that gets cancelled onPipe.StopAsync()rhubarb-geek-nz commentedon Apr 4, 2024
Agreed, I suggested that Common Parameters should include a CancellationToken.
Signals don't really fit with my idea of PowerShell, they are process owned, where as I see the point of PowerShell is to write small reusable scripts, modules, functions and cmdlets that do not own the process and are then assembled for some higher purpose to solve a problem.
My theory is that the PowerShell host itself should have the signal handler and the root console interactive session or script gets a cancellation token that will be tripped by that.
Good luck with your solution, sounds fun.
I wrote an ASP web server that uses HttpContext.RequestAborted to call PowerShell.StopAsync when a response was no longer worthwhile as the client had disconnected.
Zetanova commentedon Apr 4, 2024
I found a method to get the SIGINT signal (windows and linux) from the pwsh.exe to be useable for sync-over-async calls on Runspace1. https://gist.github.com/Zetanova/9e1a0d5e35d9ce876840b9d9b22445b3
It can be used in dotnet async method calls to be able to cancel them like with the pipe StopProcessing behavior.