Question:
For example, there are several almost identical streams that can last indefinitely.
initialization:
ParameterizedThreadStart pts = new ParameterizedThreadStart(runMethod);
Thread t = new Thread(pts);
t.Start(values);
flow:
void run(object p)
{
// нужен поток, который повторяет одно и то же с некоторой переодичностью, поэтому так:
while(true)
{
// что-то делаем
doAnything(p);
Thread.Sleep(60000);
}
}
The question is how to interrupt them adequately? It would be great if they could be interrupted while they are sleeping, or at least after doAnything ();
it is possible in the main thread to do something like
Thread t = new Thread(pts);
t.Start(values);
...
t.Abort();
but I'm not sure that some important operation will not be interrupted in the stream – loading / deleting / processing a file or some transaction will not commit
Answer:
This is done most beautifully through the CancellationToken
mechanism. This mechanism is specifically designed to pass stop and cancel messages between threads:
void run(object p)
{
var ct = (CancellationToken)p;
do
{
// что-то делаем
doAnything(p);
} while (!ct.IsCancellationRequested && !ct.WaitHandle.WaitOne(60000));
}
Here I am using waiting on an event as an interruptible alternative to Thread.Sleep
. If the wait is successful, then the thread must be stopped. If it is unsuccessful (waiting timeout), then you can continue to work.
Before waiting, I check IsCancellationRequested
to not IsCancellationRequested
kernel event when not required.
Creating a stream like this:
using (var cts = new CancellationTokenSource()) {
new Thread(run).Start(cts.Token);
...
cts.Cancel();
}
You can also use a task ( Task.Run
) instead of a thread. In this case, it is better to use Task.Delay
for waiting, this will allow you to do without kernel objects at all:
async Task run(CancellationToken ct)
{
do
{
// что-то делаем
doAnything(p);
await Task.Delay(60000, ct);
} while (!ct.IsCancellationRequested);
}
Task.Run(() => run(cts.Token));
A bonus to using CancellationToken
is the ability to pass ct
further to doAnything
– thanks to which you can finely choose at what moments an interruption of processing is allowed.
If you use the asynchronous option, then almost all the asynchronous functions of the standard library can also accept a CancellationToken
, which allows you to safely interrupt any long operation if you wish.
In older runtimes where there is no CancellationToken
mechanism,ManualResetEvent
can be used for the same purpose. The principle is the same – instead of calling Thread.Sleep
wait on the event and check the result.