Stop Threads created with ThreadPool.QueueUserWorkItem that have a specific task - c#

Let's say I queue those two methods in a for loop
for (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 output Console.WriteLine("Output"); ?

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();

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.

Related

How to run many tasks and get their result after all of them ended?

How can I obtain result(bool) of those Tasks?
public static Random rnd = new Random();
static void Main()
{
var tasks = new Task[10];
for (int i = 0; i < 10; i++)
{
tasks[i] = new Task(async () => await T());
}
Task.WaitAll(tasks);
for (int i = 0; i < tasks.Length; i++)
{
Console.WriteLine($"Task {i} result = {tasks[i].?????????}");
}
Console.ReadKey();
}
public static async Task<bool> T()
{
await Task.Delay(500);
return rnd.Next(2) == 1 ? true : false;
}
You can make Main() method async as well and use WhenAll instead of WaitAll. And use just T() when assign Task to array item, there is no need to do it like that new Task(async () => await T());
static async Task Main()
{
var tasks = new Task<bool>[10];
for (int i = 0; i < 10; i++)
{
tasks[i] = T();
}
await Task.WhenAll(tasks);
for (int i = 0; i < tasks.Length; i++)
{
Console.WriteLine($"Task {i} result = {tasks[i].Result}");
}
Console.ReadKey();
}
As #GSerg pointed out, making use of the Task constructor is considered bad practice across the industry. It's not that there is something inherently wrong with it, it just makes things more complicated than they need to be, for no good reason. If you absolutely need to use this programming technique, here is how you could do it:
var tasks = new Task<bool>[10];
for (int i = 0; i < 10; i++)
{
var task = new Task<Task<bool>>(async () => await T());
task.Start(); // Starts the outer task that creates the inner task
tasks[i] = await task;
}
await Task.WhenAll(tasks);
for (int i = 0; i < tasks.Length; i++)
{
Console.WriteLine($"Task {i} result = {await tasks[i]}");
}

How to return Task output from an anonymous method?

I've this method:
public async Task Method1Async()
{
var foo = 1;
var bar = 100;
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
// add below code here
}
await Task.WhenAll(tasks);
}
and I want to add this code to the tasks above and wait for all to finish:
// do something
await Method2Async(foo, bar);
// do something else
How can I do that? Thanks..
I tried this, but Task.WhenAll waits for ever:
public async Task Method1Async()
{
var foo = 1;
var bar = 100;
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
tasks.Add(new Task(async () =>
{
// do something
await Method2Async(foo, bar);
// do something else
}
}
await Task.WhenAll(tasks);
}
You can just add the Task directly:
tasks.Add(Method2Async(foo, bar));
If you want to do some work around it you can construct an async lambda and invoke it:
for(int i = 0; i < 10; ++i) {
Func<Task> f = async () => {
//do something
await Method2Async(foo, bar);
//do something else
}
tasks.Add(f());
}

ParallelFor not cancelling all threads immediately if condition met

Code always waits until currently running tasks have finished before the OperationCancelledException is thrown.
I would like the program to stop immediately on the condition being true.
static void Main()
{
// want to break out of a Parallel.For immediately when a condition occurs
var cts = new CancellationTokenSource();
var po = new ParallelOptions();
po.CancellationToken = cts.Token;
long counterTotal = 0;
try
{
// want to have a sum of counts at the end
Parallel.For<long>(1, 26, po, () => 0, delegate(int i, ParallelLoopState state, long counterSubtotal)
{
po.CancellationToken.ThrowIfCancellationRequested();
Console.WriteLine(i.ToString());
for (int k = 0; k < 1000000000; k++)
{
counterSubtotal++;
if (i == 4 && k == 900000000)
{
cts.Cancel();
// Would like to break out here immediately
}
}
return counterSubtotal;
}, (x) => Interlocked.Add(ref counterTotal, x)
);
}
catch (OperationCanceledException e)
{
Console.WriteLine("Cancelled");
Console.WriteLine("Total iterations across all threads {0}", String.Format("{0:n0}", counterTotal));
Console.ReadLine();
}
}
I found putting a breakpoint on cts.Cancel() and in the catch demonstrates what is happening.
Have looked at state.Stop too.
This is a simplified version of other code.
Perhaps Parallel.For isn't ideal for things which are very long running inside the method if we want to break out immediately.
Update2:
The code now works as expected and gives a good total
static void Main()
{
// want to break out of a Parallel.For immediately when a condition occurs
var cts = new CancellationTokenSource();
var po = new ParallelOptions();
po.CancellationToken = cts.Token;
long counterTotal = 0;
try
{
// want to have a sum of counts at the end
// using type param here to make counterSubtotal a long
Parallel.For<long>(1, 26, po, () => 0, delegate(int i, ParallelLoopState state, long counterSubtotal)
{
Console.WriteLine(i.ToString());
// 1 billion
for (int k = 0; k < 1000000000; k++)
{
//po.CancellationToken.ThrowIfCancellationRequested();
if (po.CancellationToken.IsCancellationRequested)
{
return counterSubtotal;
}
counterSubtotal++;
if (i == 4 && k == 400000000)
{
Console.WriteLine("Inner Cancelled");
cts.Cancel();
}
}
return counterSubtotal;
}, (x) => Interlocked.Add(ref counterTotal, x)
);
}
catch (OperationCanceledException e)
{
Console.WriteLine("Cancelled");
Console.WriteLine("Total iterations across all threads {0}", String.Format("{0:n0}", counterTotal));
Console.ReadLine();
}
}
If you want it to break more "immediately" than you need to check the cancellation token inside of your inner for. As it is now, it will check for cancel before entering, but after that it won't look at the token again.
for (int k = 0; k < 1000000000; k++)
{
po.CancellationToken.ThrowIfCancellationRequested();
counterSubtotal++;
if (i == 4 && k == 900000000)
{
cts.Cancel();
}
}

Wait for threads to complete

private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 15; i++)
{
Thread nova = new Thread(Method);
nova.Start();
}
listBox1.Items.Add("Some text");
}
private void Method()
{
for (int i = 0; i < 15; i++)
{
Console.WriteLine(i);
}
}
This code does write: Some text and then numbers 111222333.....
I would like that it writes 111122223333.... and then on the end Some text.
is it possible to do that with threads (parent thread wait for child threads)? or do i have to use something else?
You need to keep track of all the threads, and use Thread.Join on each one. This waits until the specified thread terminates, and then continues executing. Like this:
var threads = new List<Thread>();
for (int i = 0; i < 15; i++)
{
Thread nova = new Thread(Method);
nova.Start();
threads.Add(nova);
}
foreach (var thread in threads)
thread.Join();
listBox1.Items.Add("Some text");
I suggest to use TPL to get this done. You won't need to spawn so many threads. By default TPL will use thread pool for that:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
private const int TaskCount = 15;
static void Main(string[] args)
{
var tasks = new Task[TaskCount];
for (var index = 0; index < TaskCount; index++)
{
tasks[index] = Task.Factory.StartNew(Method);
}
Task.WaitAll(tasks);
Console.WriteLine("Some text");
}
private static void Method()
{
for (int i = 0; i < 15; i++)
{
Console.WriteLine(i);
}
}
}
}
You could have two threads, the 2nd one waiting on a signal to fire from the first.
private void Foo()
{
var signals = new List<ManualResetEvent>();
for (int i = 0; i < 15; i++)
{
var signal = new ManualResetEvent(false);
signals.Add(signal);
var thread = new Thread(() => { Method(); signal.Set(); });
thread.Start();
}
var completionTask = new Thread(() =>
{
WaitHandle.WaitAll(signals.ToArray());
CompletionWork();
});
completionTask.Start();
}
private void Method()
{
}
private void CompletionWork()
{
}
The better solution now with .Net 4.0 (and later) is to use Tasks, and invoke a method using ContinueWith
private void Foo()
{
var childThreads = new List<Task>();
for (int i = 0; i < 15; i++)
{
var task = new Task(Method);
task.Start();
childThreads.Add(task);
}
var completionTask = new Task(() =>
{
Task.WaitAll(childThreads.ToArray());
}).ContinueWith(t => CompletionWork());
}
private void Method()
{
}
private void CompletionWork()
{
}
The join answers also work, but require the containing thread to block. If you don't want the GUI to block, Spawn an additional thread around the 1st.
You can use thread.join to wait for threads to end. See http://www.dotnetperls.com/thread-join for an page on how to use it.

C# Maintain 3 threads and close one if it takes to long

This is the code I am using to call 3 threads.
for (int i = 0; i < 3; i++)
{
new Thread(() => { processEventLogTesting(); }) {IsBackground = true }.Start();
}
I was thinking about adjusting it to this
public static int ThreadCounter = 0;
if (ThreadCounter < 3)
{
ThreadCounter ++;
for (int i = 0; i < 3; i++)
{
new Thread(() =>
{
processEventLogTesting(/*somewhere in here code says */ThreadCounter--;);}) {IsBackground = true }.Start();
}
}
}
However, I think this is probably not the best way to do this. Also, I want to put in a new timer that says if thread x goes over 20 minutes, kill thread x. Any help is appreciated.
Since I don't know what thread does, I would try something like this
private Object lockObject = new Object();
private int threadCounter = 0;
public int ThreadCounter
{
get
{
lock(lockObject)
{
return threadCounter;
}
}
set
{
lock(lockObject)
{
threadCounter = value;
}
}
}
//this should be a method
if (ThreadCounter < 3)
{
ThreadCounter ++;
new Thread(() =>
{
Timer t = new Timer(() => EndThread(), null, 0, 20 * 60 * 1000);
while(threadIsRunning)
{
processEventLogTesting(/*somewhere in here code says ThreadCounter--*/;);
}
}) {IsBackground = true }.Start();
}
}
}
private void EndThread()
{
threadIsRunning = false;
}

Categories