I got a requirement where I need to process two Threads simultaneously in a ForLoop.
For Example :
private void BtnThreading_Click(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
Thread thread1 = new Thread(ProcessA);
thread1.Start();
thread1.Join();
Thread thread2 = new Thread(ProcessB);
thread2.Start();
}
}
private void ProcessA()
{
Thread.Sleep(10000);
}
private void ProcessB()
{
Thread.Sleep(20000);
}
For the First Time in the for-loop,Let's say the ProcessA() takes 10 Seconds to complete and I need to wait till the ProcessA() to finish using thread1.Join(); to Start Processing ProcessB().Later the ProcessB() starts and it will take 20 seconds to finish.
So,In the mean while ProcessA() again starts and thread1.Join(); statement will wait until ProcessA() finishes.Here I need to wait also for the previous ProcessB() to finish.
so finally,I want the ProcessB() to wait for the Previous Thread of ProcessB()
Sorry for my Bad English !!! :)
Unless your really need to do low level programming you should not use Thread objects directly. Each thread is quite expensive in terms of resources. Instead .NET provides several high level abstractions to do asynchronous and parallel programming. Your loop can be built using async and await and will then execute on thread pool threads. Here is an example:
Instead of using Thread.Sleep to simulate delay you have to use Task.Delay:
async Task ProcessA() {
await Task.Delay(10000);
}
async Task ProcessB() {
await Task.Delay(20000);
}
The loop:
var task = Task.Delay(0); // No operation task to simplify loop.
for (var i = 0; i < 20; i += 1) {
await ProcessA();
await task;
task = ProcessB();
}
await task;
It looks like you don't really need ProcessA to execute in a different thread at all - but you do need to keep track of your previous ProcessB thread. So something like:
Thread previousThread = null;
for (int i = 0; i < 20; i++)
{
ProcessA();
if (previousThread != null)
{
previousThread.Join();
}
previousThread = new Thread(ProcessB);
previousThread.Start();
}
// Possibly join on previousThread here too
Note that your method name suggests that you're doing this in a UI thread - which you really, really shouldn't. Don't block the UI thread for any length of time - and remember that Join is a blocking call.
You can give this code a try, but again it is not production ready..!!!
Thread thread1 = null;
Thread thread2 = null;
private void BtnThreading_Click(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
thread1 = new Thread(ProcessA);
thread1.Start();
thread1.Join();
if (thread2 != null)
thread2.Join();
thread2 = new Thread(ProcessB);
thread2.Start();
}
}
Related
I try to pause all my threads when I reach a certain value but I can't do it.
I would like that when I reach this value all threads are paused for 10 seconds and after these 10 seconds all threads start again.
I tried that with : Threads.Sleep(); | Threads.Interrupt(); and Threads.Abort(); but nothing work.
I tried what you can see in the code below.
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Threads.Add(new Thread(new ThreadStart(example)));
Threads[i].Start();
}
for (int i = 0; i < Threads.Count; i++)
Threads[i].Join();
}
static void example()
{
while (true)
{
Console.WriteLine(value++);
checkValue();
}
}
public static void checkValue()
{
if (value% 1000 == 0 && value!= 0)
{
for (int i = 0; i < Threads.Count; i++)
Threads[i].Interrupt();
Thread.Sleep(1000);
for (int i = 0; i < Threads.Count; i++)
Threads[i].Resume();
}
}
Here is an example of pausing some threads cooperatively, by using the PauseTokenSource + PauseToken pair from Stephen Cleary's AsyncEx.Coordination package. This example shows also the use of the analogous CancellationTokenSource + CancellationToken pair, that inspired the creation of the aforementioned pausing mechanism.
var pts = new PauseTokenSource() { IsPaused = true };
var cts = new CancellationTokenSource();
int value = 0;
// Create five threads
Thread[] threads = Enumerable.Range(1, 5).Select(i => new Thread(() =>
{
try
{
while (true)
{
cts.Token.ThrowIfCancellationRequested(); // self explanatory
pts.Token.WaitWhilePaused(cts.Token); // ...and don't wait if not paused
int localValue = Interlocked.Increment(ref value);
Console.WriteLine($"Thread #{i}, Value: {localValue}");
}
}
catch (OperationCanceledException) // this exception is expected and benign
{
Console.WriteLine($"Thread #{i} Canceled");
}
})).ToArray();
// Start the threads
foreach (var thread in threads) thread.Start();
// Now lets pause and unpause the threads periodically some times
// We use the main thread (the current thread) as the controller
Thread.Sleep(500);
pts.IsPaused = false;
Thread.Sleep(1000);
pts.IsPaused = true;
Thread.Sleep(1000);
pts.IsPaused = false;
Thread.Sleep(1000);
pts.IsPaused = true;
Thread.Sleep(500);
// Finally cancel the threads and wait them to finish
cts.Cancel();
foreach (var thread in threads) thread.Join();
You may need to read this first, to get a grasp on the model used by the .NET platform for cooperative cancellation. Cooperative "pausation" is very similar.
I have a console application with have two threads as:
public static async void Thread1()
{
for (int i = 0; i < 100; i++)
{
Debug.WriteLine("Thread1 " + i);
await MyFunc();
}
}
public static async void Thread2()
{
for (int i = 0; i < 100; i++)
{
Debug.WriteLine("Thread2 " + i);
await MyFunc();
}
}
public static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
private static async Task MainAsync(string[] args)
{
Console.WriteLine("Before start thread");
Thread tid1 = new Thread(Thread1);
Thread tid2 = new Thread(Thread2);
tid1.Start();
tid2.Start();
}
public static async Task MyFunc()
{
//do something
}
However, when the application run and terminates, it seems that only each thread is run just once as I see only below things in output:
Before start thread
Thread1 0
Thread2 0
//some thing from MyFunc
I expect or rather wannt to run each thread till the for loop.It seems to me that the for loop continues to run despite the await.
If yes, what could be other probable approach.
Any leads would be helpful.
You aren't doing anything to wait for the threads. The main routine will just continue on until it returns to the O/S, which will kill the process and any child threads. Since you aren't doing anything else, this happens almost immediately, cutting both threads' lives short.
If you want to wait for the threads to finish, you can refer to this answer and write some variation of
while (thread1.IsAlive || thread2.IsAlive)
{
//Do something to wait
}
...before exiting.
That being said, you should probably using Tasks instead of threads, e.g.
public static async Task Task1()
{
for (int i = 0; i < 100; i++)
{
Debug.WriteLine("Task1 " + i);
await MyFunc();
}
}
public static async Task Task2()
{
for (int i = 0; i < 100; i++)
{
Debug.WriteLine("Task2 " + i);
await MyFunc();
}
}
And then to execute and wait for both of them:
Task.WaitAll
(
new[]
{
Task1(),
Task2()
}
);
See this code in action on DotNetFiddle
See also What is the difference between tasks and threads?
You seem to have a lot of confusion about the role of threads and tasks, so it's a good idea to read up about it. Steven Cleary has a nice write-up about this. "There Is No Thread"
From the comments, it seems that your actual intention here is to run two async tasks in parallel, then to wait until they are both finished.
If you want to wait for two async tasks to complete in parallel, make sure your async methods actually return Task then:
Task task1 = DoSomethingAsync(); //don't await
Task task2 = DoSomethingElseAsync(); //don't await
then you can wait asynchronously for Task.WhenAll:
await Task.WhenAll(task1,task2);
You really don't need to be involving Thread at all.
Use async Task instead of async void
private static async Task MainAsync(string[] args)
{
Console.WriteLine("Before start thread");
var task1 = Thread1();
var task2 = Thread2();
var taskList = new [] { task1, task2 };
Task.WaitAll(taskList);
}
I'm looking for a fast way to let many worker threads wait for an event to continue and block the main thread until all worker threads are finished. I first used TPL or AutoResetEvent but since my calculation isn't that expensive the overhead was way too much.
I found a pretty interesting article concerning this problem and got great results (using only one worker thread) with the last synchronization solution (Interlocked.CompareExchange). But I don't know how to utilize it for a scenario where many threads wait for one main tread repeatedly.
Here is an example using single thread, CompareExchange, and Barrier:
static void Main(string[] args)
{
int cnt = 1000000;
var stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < cnt; i++) { }
Console.WriteLine($"Single thread: {stopwatch.Elapsed.TotalSeconds}s");
var run = true;
Task task;
stopwatch.Restart();
int interlock = 0;
task = Task.Run(() =>
{
while (run)
{
while (Interlocked.CompareExchange(ref interlock, 0, 1) != 1) { Thread.Sleep(0); }
interlock = 2;
}
Console.WriteLine($"CompareExchange synced: {stopwatch.Elapsed.TotalSeconds}s");
});
for (int i = 0; i < cnt; i++)
{
interlock = 1;
while (Interlocked.CompareExchange(ref interlock, 0, 2) != 2) { Thread.Sleep(0); }
}
run = false;
interlock = 1;
task.Wait();
run = true;
var barrier = new Barrier(2);
stopwatch.Restart();
task = Task.Run(() =>
{
while (run) { barrier.SignalAndWait(); }
Console.WriteLine($"Barrier synced: {stopwatch.Elapsed.TotalSeconds}s");
});
for (int i = 0; i < cnt; i++) { barrier.SignalAndWait(); }
Thread.Sleep(0);
run = false;
if (barrier.ParticipantsRemaining == 1) { barrier.SignalAndWait(); }
task.Wait();
Console.ReadKey();
}
Average results (in seconds) are:
Single thread: 0,002
CompareExchange: 0,4
Barrier: 1,7
As you can see Barriers' overhead seems to be arround 4 times higher! If someone can rebuild me the CompareExchange-scenario to work with multiple worker threads this would surely help, too!
Sure, 1 second overhead for a million calculations is pretty less! Actually it just interests me.
Edit:
System.Threading.Barrier seems to be the fastest solution for this scenario. For saving a double blocking (all workers ready for work, all workes finished) I used the following code for the best results:
while(work)
{
while (barrier.ParticipantsRemaining > 1) { Thread.Sleep(0); }
//Set work package
barrier.SignalAndWait()
}
It seems like you might want to use a Barrier to synchronise a number of workers with a main thread.
Here's a compilable example. Have a play with it, paying attention to when the output tells you that you can "Press <Return> to signal the workers to start".
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
static class Program
{
static void Main()
{
print("Main thread is starting the workers.");
int numWorkers = 10;
var barrier = new Barrier(numWorkers + 1); // Workers + main (controlling) thread.
for (int i = 0; i < numWorkers; ++i)
{
int n = i; // Prevent modified closure.
Task.Run(() => worker(barrier, n));
}
while (true)
{
print("***************** Press <RETURN> to signal the workers to start");
Console.ReadLine();
print("Main thread is signalling all the workers to start.");
// This will wait for all the workers to issue their call to
// barrier.SignalAndWait() before it returns:
barrier.SignalAndWait();
// At this point, all workers AND the main thread are at the same point.
}
}
static void worker(Barrier barrier, int workerNumber)
{
int iter = 0;
while (true)
{
print($"Worker {workerNumber} on iteration {iter} is waiting for barrier.");
// This will wait for all the other workers AND the main thread
// to issue their call to barrier.SignalAndWait() before it returns:
barrier.SignalAndWait();
// At this point, all workers AND the main thread are at the same point.
int delay = randomDelayMilliseconds();
print($"Worker {workerNumber} got barrier, now sleeping for {delay}");
Thread.Sleep(delay);
print($"Worker {workerNumber} finished work for iteration {iter}.");
}
}
static void print(string message)
{
Console.WriteLine($"[{sw.ElapsedMilliseconds:00000}] {message}");
}
static int randomDelayMilliseconds()
{
lock (rng)
{
return rng.Next(10000) + 5000;
}
}
static Random rng = new Random();
static Stopwatch sw = Stopwatch.StartNew();
}
}
I am new to threading concept, using threading first time in my application. One of my application processing multiple data, without threading it is taking approx 2 minutes while with help of threading it is taking just 25 seconds, but i want notification when all threads finishes work.
private int z = 0 ;
startfunction()
{
z= 250;
start1step(z);
}
private void start1step(int i)
{
if (i < 0)
return;
else
{
Thread thread = new Thread(new ThreadStart(WorkThreadFunction));
thread.Start();
start1step( --i);
}
}
public void WorkThreadFunction( )
{
try
{
int x = z ;
z-- ;
// do some background work
if(x ==0)
MessageBox.Show("All Thread finished");
}
catch
{
//
}
}
Above sample code is working perfectly except that notification part, I want notification when all threads finishes background work. There is one last step left which sums up work finished by all these threads.
Please help
There are lots of ways to do this. I would say the two most convenient methods that remain similar to your current implementation involve using a CountDownEvent or switching to the Task class for your threading. A third method involves using the Parallel.ForEach() method, and that might actually suit your specific scenario better.
CountDownEvent looks like this:
CountDownEvent countDown = new CountDownEvent(250);
startfunction()
{
countDown.Reset();
start1step(250);
countDown.Wait();
}
private void start1step(int i)
{
while (i-- > 0)
{
new Thread(WorkThreadFunction, i).Start();
}
}
public void WorkThreadFunction(object o)
{
int x = (int)o;
try
{
// do some background work
}
catch
{
//
}
finally
{
countDown.Signal();
}
}
Task looks like this:
startfunction()
{
Task[] tasks = new Task[250];
start1step(tasks);
Task.WaitAll(tasks);
}
private void start1step(Task[] tasks)
{
for (int i = 0; i < tasks.Length; i++)
{
int taskParam = i;
tasks[i] = Task.Run(() => WorkThreadFunction(taskParam));
}
}
public void WorkThreadFunction(int x)
{
try
{
// do some background work
}
catch
{
//
}
}
Parallel.ForEach() looks like this:
startfunction()
{
Parallel.ForEach(Enumerable.Range(0, 250), i => WorkThreadFunction(i));
}
public void WorkThreadFunction(int x)
{
try
{
// do some background work
}
catch
{
//
}
}
In your main thread you can do something like this...
List<Thread> threads = new List<Thread>();
// CREATE THREADS and add them to the list of threads
while (threads.Any(x => x.IsAlive))
{
Thread.Sleep(500);
}
Console.WriteLine("done");
Essentially, keep track of the threads and check their status every now and then in a way that doesn't block the main thread.
My goal is to create a system that spawns an initial number of tasks(all the same). These tasks will grab and perform some background operation (from a DB) and then return, at which point a new task should spawn and do the same thing.
I have written the following code as a proof of concept, but it seems like all my tasks are executing 1 by 1, not in parallel.
Code:
public Form1()
{
InitializeComponent();
}
CancellationTokenSource cts;
private async void button1_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
int reqNumberOfThreads = int.Parse(textBox1.Text);
try
{
await startSlaves(cts.Token, reqNumberOfThreads);
}
catch (OperationCanceledException)
{
MessageBox.Show("Canceled Starting Threads");
}
cts = null;
}
async Task startSlaves(CancellationToken ct, int threadNum)
{
List<Task<int>> allTasks = new List<Task<int>>();// ***Add a loop to process the tasks one at a time until none remain.
for (int x = 0; x < threadNum; x++)
{
allTasks.Add(beginSlaveOperation(ct, x));
}
// ***Add a loop to process the tasks one at a time until none remain.
while (allTasks.Count <= threadNum)
{
// Identify the first task that completes.
Task<int> output = await Task.WhenAny(allTasks);
allTasks.Remove(output);
allTasks.Add(beginSlaveOperation(ct, output.Result));
}
}
public void performExampleImportOperationThread(int inputVal, int whoAmI)
{
System.Threading.Thread.Sleep(inputVal*10);
System.Console.Write("Thread number" + whoAmI.ToString() + "has finished after "+inputVal.ToString()+" secs \n");
}
async Task<int> beginSlaveOperation(CancellationToken ct, int whoAmI)
{
Random random = new Random();
int randomNumber = random.Next(0, 100);//Get command from microSched and remove it from sched
performExampleImportOperationThread(randomNumber, whoAmI);//perform operation
return whoAmI;
}
private void button2_Click(object sender, EventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
Output:
Thread number0has finished after 29 secs
Thread number1has finished after 45 secs
Thread number2has finished after 59 secs
Thread number0has finished after 39 secs
Thread number1has finished after 13 secs
Thread number2has finished after 44 secs
Thread number0has finished after 21 secs
Thread number1has finished after 62 secs
Thread number2has finished after 62 secs
Thread number0has finished after 25 secs
Thread number1has finished after 86 secs
Thread number2has finished after 10 secs
Thread number0has finished after 4 secs
Thread number1has finished after 24 secs
Thread number2has finished after 84 secs
Thread number0has finished after 73 secs
Thread number1has finished after 19 secs
Thread number2has finished after 72 secs
Thread number0has finished after 82 secs
Your beginSlaveOperation is marked as async, and you call it as if it were asynchronous, but you never actually await anything, so it is going to run synchronously. (Which makes its caller run synchronously, and its caller run synchronously, and so on, so that your entire application is running synchronously.)
Marking a method async doesn't magically make it run in a new thread. All it does is let you use the await keyword. If you don't ever use it, all you've done is execute a bunch of code synchronously and wrap the result in a completed task. You should even get a compiler warning for doing this.
You can fix that by having performExampleImportOperationThread be an async method and, instead of using Thread.Sleep(...), use await Task.Delay(...). That await performExampleImportOperationThread to make beginSlaveOperation actually be asynchronous.
Or you could just not do everything that you're doing and replace it all with a call to Parallel.For, which can set a MaxDegreesOfParallelism to limit you to a specific number of concurrent threads.
Here's the fixed code for future reference:
public Form1()
{
InitializeComponent();
}
CancellationTokenSource cts;
private async void button1_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
int reqNumberOfThreads = int.Parse(textBox1.Text);
try
{
await startSlaves(cts.Token, reqNumberOfThreads);
}
catch (OperationCanceledException)
{
MessageBox.Show("Canceled Starting Threads");
}
cts = null;
}
async Task startSlaves(CancellationToken ct, int threadNum)
{
List<Task<int>> allTasks = new List<Task<int>>();// ***Add a loop to process the tasks one at a time until none remain.
for (int x = 0; x < threadNum; x++)
{
allTasks.Add(beginSlaveOperation(ct, x));
}
// ***Add a loop to process the tasks one at a time until none remain.
while (allTasks.Count <= threadNum)
{
// Identify the first task that completes.
Task<int> output = await Task.WhenAny(allTasks);
allTasks.Remove(output);
allTasks.Add(beginSlaveOperation(ct, output.Result));
}
}
public async Task performExampleImportOperationThread(int inputVal, int whoAmI)
{
await Task.Delay(inputVal*100);
System.Console.Write("Thread number" + whoAmI.ToString() + "has finished after "+inputVal.ToString()+" secs \n");
}
async Task<int> beginSlaveOperation(CancellationToken ct, int whoAmI)
{
Random random = new Random();
int randomNumber = random.Next(0, 100);//Get command from microSched and remove it from sched
await performExampleImportOperationThread(randomNumber, whoAmI);//perform operation
return whoAmI;
}
private void button2_Click(object sender, EventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}