Stop Threads created with ThreadPool.QueueUserWorkItem that have a specific task
22,974
Solution 1
You could use a CancellationToken:
for (int i = 0; i < 100; i++)
{
ThreadPool.QueueUserWorkItem(s =>
{
Console.WriteLine("Output");
Thread.Sleep(1000);
});
}
CancellationTokenSource cts = new CancellationTokenSource();
for (int i = 0; i < 100; i++)
{
ThreadPool.QueueUserWorkItem(s =>
{
CancellationToken token = (CancellationToken) s;
if (token.IsCancellationRequested)
return;
Console.WriteLine("Output2");
token.WaitHandle.WaitOne(1000);
}, cts.Token);
}
cts.Cancel();
Solution 2
No, you can't do that. If you want to do something a long the lines then you must write some code to manage it. At the very basic level you need something like this:
object syncObject = new object();
bool shouldOutput2 = true;
ThreadPool.QueueUserWorkItem(s =>
{
lock(syncObject)
{
if(!shouldOutput2)
{
return;
}
}
Console.WriteLine("Output2");
Thread.Sleep(1000);
});
Once you queue the items, then you can set the flag in order to tell the remaining items not to execute:
lock(syncObject)
{
shouldOutput2 = false;
}
This is a very dirty way of doing it, but it seems like the only way given your example. If you can tell us more about what is the actual real-world behavior you're trying to accomplish, then there could be some better options.
Author by
maddo7
Updated on July 16, 2022Comments
-
maddo7 almost 2 years
Let's say I queue those two methods in a
for
loopfor (int i = 0; i < 100; i++) { ThreadPool.QueueUserWorkItem(s => { Console.WriteLine("Output"); Thread.Sleep(1000); }); } for (int i = 0; i < 100; i++) { ThreadPool.QueueUserWorkItem(s => { Console.WriteLine("Output2"); Thread.Sleep(1000); }); }
Is there a way to stop all the threads that output
Console.WriteLine("Output2");
but keep the ones running that outputConsole.WriteLine("Output");
?-
Furqan Safdar over 11 yearsI am not really able to completely understand your requirement. You can just don't start that particular task based on some condition. As you must be needing some condition to decide.
-
Furqan Safdar over 11 yearsBy the way this is method (not thread) that is executed by the available thread in the ThreadPool.
-
Servy over 11 yearsWhat version of C# are you using? Is it 4.0+? If so, you should ideally be using
Task
objects instead, and it would help greatly at addressing this problem. -
maddo7 over 11 yearsdo you have a resource where I could read about putting like 2k tasks into a pool and then having only 50 tasks run at a time till all tasks are complete like the threadpool?
-
-
Servy over 11 yearsThis assumes the OP is on .NET 4.0+, which he may not be (given that he's using the thread pool directly and not tasks). If he is, then this is the way to go.
-
Servy over 11 yearsThe placement of your lock takes the 100 items previously executed in parallel and runs them serially. The lock should only cover the
if
. -
Kiril over 11 years@Servy ah, yes! Thanks for that catch, I've moved the execution outside the lock+check.
-
Servy over 11 yearsUsing a
CancellationToken
is much cleaner, as it takes care of the synchronization issues for you, but since it's plausible the OP doesn't have .NET 4.0 it's beneficial to have this here. -
jaket over 11 yearsIf using < 4.0, the cancellation token could be replaced with a ManualResetEvent.
-
ToolmakerSteve over 7 years@jaket - (if I understand correctly) ManualResetEvent is for a different situation than CancellationToken. It is used for controlling when a thread STARTS executing. It CAN help with threads that have not yet begun. But it does not help STOP threads that have already begun executing. For that, before .Net 4.0, programmer must write their own code, like Lirik's answer.
-
ToolmakerSteve over 7 yearsThis answer, as written, only helps if the queued object has not yet started running. To stop a long-running operation containing a loop, place the test inside the loop.
while (..) { if (!shouldContinue) return; ... }
-
ToolmakerSteve over 7 yearsI just realized Lirik's answer has the same limitation. I see that the question was worded ambiguously. See my comment there for how to adapt the code for stopping a long-running task, before .Net 4.0.
-
jaket over 7 years@ToolmakerSteve. ManualResetEvent can be used for many purposes beyond starting a thread. In the example above the token.IsCancellationPending could be replaced with mre.WaitOne(0) and the token.WaitHandle.WaitOne(1000) with mre.WaitOne(1000). There is nothing to STOP a thread short of an Abort (which is a horrible idea) other than polling something - like the bool in Links answer, a MRE which is like a waitable bool or a CancellationToken which is more robust and designed specifically for this purpose.