Iv feel a bit lost find a good way to get some ideas of how to solve my threading problem C# Unity. What I try to achieve is to offload my main thread from long running tasks. This to avoid the main thread to wait for a or several tasks to finish before the main thread can continue as usual.
Right now I have this test code.
public void Start()
{
var workers = new List<DataChunk>();
workers.Add(new DataChunk());
workers.Add(new DataChunk());
foreach (var worker in workers)
{
Task.Run(() => worker);
}
}
The DataChunck is just striped down here for this test and could contain all the procedures that are suppose to be included as a complete task. So right now I just have a timer here to simulate something being done and taking its time.
public class DataChunk
{
public bool isDone = false;
public DataChunk()
{
System.Random r = new System.Random();
int rInt = r.Next(1000, 2000);
Thread.Sleep(rInt);
allDataLoaded = true;
Debug.Log("Done " + rInt);
isDone = true;
}
}
This dose not really do what I want to achieve in the end, as it only executes these the DataChunks executed as tasks in a row, never letting go of the main thread.
What I believe is missing is making this asyc, so they can be started from the main thread, and then preferably without having to waiting for completion from the main thread. As this should be checked from a queue when ever possible.
Should work something like this if I ware to visualize it.
Anyone who would like to share what is missing to achieve a threaded or task based behavior like this?
You are calling to Thread.Sleep in DataChunk constructor: workers.Add(new DataChunk()), and because of this your Thread.Sleep steps are executed not in parallel.
It's better to move Thread.Sleep logic outside of DataChunk constructor to some DataChunk class method and call this method from Task.Run(() => worker.SomeMethodWithThreadSleep());
I have a function which is going to be processed by like 5 threads at same time but with different arguments passed. I want to wait to make the main thread wait for the rest threads and then release it. I'm not even sure if CancellationToken would work with Threadpool because all examples are with Tasks and I want to set up a button to stop threads at some point.
I'm aware of the fact there is a lot of information about threading but that's the actual problem. I don't know which threading classes are better or how to implement them because there are ambiguous examples. One source says that it should be done in one way and another in other way. Here are some examples that I saw. You can see that MSDN's example is ambiguous compared to the other 2 links or at least I'm missing the point. https://jeremylindsayni.wordpress.com/2016/03/26/how-to-use-manualresetevent-in-c-to-block-one-thread-until-another-has-completed/, How to make main thread to wait until other threads ends and https://learn.microsoft.com/en-us/dotnet/api/system.threading.manualresetevent?view=netframework-4.7.2.
private void DoJob(object state)
{
Console.WriteLine("Delaying...");
Thread.Sleep(3000);
Console.WriteLine("Thread done");
_manualResetEvent.Set();
}
// on some button click event
_manualResetEvent = new ManualResetEvent(false);
for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoJob), i);
}
_manualResetEvent.WaitOne();
Console.WriteLine("Main thread released");
In the example above, I wanted to make main thread wait for rest threads until they are done but the main thread is getting released after the first thread is done.
Delaying...
Delaying...
Delaying...
Delaying...
Thread done
Main thread released
Thread done
Thread done
Thread done
If I put WaitOne in each thread (DoJob method) and Set on the place of current WaitOne, the main thread is being released first and what I want is to release it after all other threads are done.
In your case, you really just use tasks:
var tasks = new List<Task>();
for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
tasks.Add(Task.Run(() => DoJob(i)));
}
Task.WaitAll(tasks);
If for some reason you don't want to use tasks, you can have a look at CountdownEvent, which is precisely designed to wait on a definite number of asynchronous operations:
private void DoJob(object state)
{
Console.WriteLine("Delaying...");
Thread.Sleep(3000);
Console.WriteLine("Thread done");
_countdownEvent.Signal();
}
// on some button click event
_countdownEvent = new CountdownEvent(threadsNumericUpDown.Value);
for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoJob), i);
}
_countdownEvent.Wait();
Console.WriteLine("Main thread released");
I have a simple program here below that has 2 threads performing some task.
Thread1 is the data feeder. Thread2 is the data processor.
So far the work being done through my approach is working but I want to have better way of getting notified when the work completes
Here is the code
class Program
{
private static BlockingCollection<int> _samples = new BlockingCollection<int>();
private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private static bool _cancel;
static void Main(string[] args)
{
ThreadStart thread1 = delegate
{
ProcessThread1();
};
new Thread(thread1).Start();
ThreadStart thread2 = delegate
{
ProcessThread2();
};
new Thread(thread2).Start();
Console.WriteLine("Press any key to cancel..");
Console.Read();
_cancel = true;
_cancellationTokenSource.Cancel();
Console.Read();
}
private static void ProcessThread1()
{
for (int i = 0; i < 10; i++)
{
if (_cancel)
{
break;
}
Console.WriteLine("Adding data..");
_samples.TryAdd(i,100);
Thread.Sleep(1000);
}
// I dont like this. Instead can I get notified in the UI thread that this thread is complete.
_cancel = true;
_cancellationTokenSource.Cancel();
}
private static void ProcessThread2()
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
int data;
if (_samples.TryTake(out data, 100))
{
// Do some work.
Console.WriteLine("Processing data..");
}
}
Console.WriteLine("Cancelled.");
}
}
I want the program to exit if the cancel is requested by the user or when the work completes.
I am not sure how I can get notified when the ProcessThread1 runs out of work. Currently I am setting cancel = true when the work is complete but it seem not right. Any help appreciated.
If you use Task instead of manually creating threads, you can attach a continuation on your task to notify your UI that the work is complete.
Task workOne = Task.Factory.StartNew( () => ProcessThread1());
workOne.ContinueWith(t =>
{
// Update UI here
}, TaskScheduler.FromCurrentSynchronizationContext());
With .NET 4.5, this becomes even easier, as you can potentially use the new async language support:
var workOne = Task.Run(ProcessThread1);
var workTwo = Task.Run(ProcessThread2);
// asynchronously wait for both tasks to complete...
await Task.WhenAll(workOne, workTwo);
// Update UI here.
Note that these both are designed with a user interface in mind - and will behave unusually in a console application, as there is no current synchronization context in a console application. When you move this to a true user interface, it will behave correctly.
Start one more thread whose only job is to wait on console input:
private void ConsoleInputProc()
{
Console.Write("Press Enter to cancel:");
Console.ReadLine();
_cancellationTokenSource.Cancel();
}
Your main thread then starts the two processing threads and the input thread.
// create and start the processing threads
Thread t1 = new Thread(thread1);
Thread t2 = new Thread(thread2);
t1.Start();
t2.Start();
// create and start the input thread
Thread inputThread = new Thread(ConsoleInputProc);
inputThread.Start();
Then, you wait on the two processing threads:
t1.Join();
// first thread finished. Request cancellation.
_cancellationTokenSource.Cancel();
t2.Join();
So if the user presses Enter, then the input thread sets the cancellation flags. thread1 and thread2 both see the cancellation request and exit.
If thread1 completes its work, then the main thread sets the cancellation flag and thread2 will cancel.
In either case, the program won't exit until thread 2 exits.
There's no need to kill the input thread explicitly. It will die when the program exits.
By the way, I would remove these lines from the thread 1 proc:
// I dont like this. Instead can I get notified in the UI thread that this thread is complete.
_cancel = true;
_cancellationTokenSource.Cancel();
I would remove the _cancel variable altogether, and have the first thread check IsCancellationRequested just like the second thread does.
It's unfortunate that you have to start a dedicated thread to wait on console input, but it's the only way I know of to accomplish this. The Windows console doesn't appear to have a waitable event.
Note that you could do this same thing with Task, which overall is easier to use. The code that the tasks perform would be the same.
Update
Looking at the bigger picture, I see that you have a typical producer/consumer setup with BlockingCollection. You can make your producer and consumer threads a lot cleaner:
private static void ProcessThread1()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Adding data..");
_samples.TryAdd(i, Timeout.Infinite, _cancellationTokenSource.Token);
// not sure why the sleep is here
Thread.Sleep(1000);
}
// Marks the queue as complete for adding.
// When the queue goes empty, the consumer will know that
// no more data is forthcoming.
_samples.CompleteAdding();
}
private static void ProcessThread2()
{
int data;
while (_samples.TryTake(out data, TimeSpan.Infinite, _cancellationTokenSource.Token))
{
// Do some work.
Console.WriteLine("Processing data..");
}
Console.WriteLine("Cancelled.");
}
You'll still need that input thread (unless you want to spin a loop on Console.KeyAvailable), but this greatly simplifies your producer and consumer.
I am trying to get 2 threads running in the background to perform tasks. I have to create the threads sequentially and proceed with the program execution. But the second thread must execute it's work only when the first finishes. Also, One more clarification. I am looking to have this solution on a WPF application. There is no UI feedback needed. All I need is a status update from the first task. I agree if we do all in one thread it will be fine. But we want to have the second thread which does more things seperately even if the user leaves the screen which created this thread.
Here is the sample:
class Program
{
static string outValue;
static bool _isFinished = false;
static void Main(string[] args)
{
ThreadStart thread1 = delegate()
{
outValue = AnotherClass.FirstLongRunningTask();
// I need to set the _isFinished after the long running finishes..
// I cant wait here because I need to kick start the next thread and move on.
//
};
new Thread(thread1).Start();
ThreadStart thread2 = delegate()
{
while (!_isFinished)
{
Thread.Sleep(1000);
Console.WriteLine("Inside the while loop...");
}
if (!string.IsNullOrEmpty(outValue))
{
// This should execute only if the _isFinished is true...
AnotherClass.SecondTask(outValue);
}
};
new Thread(thread2).Start();
for (int i = 0; i < 5000; i++)
{
Thread.Sleep(500);
Console.WriteLine("I have to work on this while thread 1 and thread 2 and doing something ...");
}
Console.ReadLine();
}
}
public class AnotherClass
{
public static string FirstLongRunningTask()
{
Thread.Sleep(6000);
return "From the first long running task...";
}
public static void SecondTask(string fromThread1)
{
Thread.Sleep(1000);
Console.WriteLine(fromThread1);
}
}
Where do I set the _isFinished?
I can't use BackgroundWorker threads. Any help is appreciated.
If a thread can only start when another one finishes, you have a very simple solution: execute the entire code on the first thread.
You can use Task.ContinueWith to queue up more work for the same Task.
You should simply call thread1.Join(), which will block until thread1 terminates.
However, there are a large number of better ways to do this.
You should use the TPL and the Task class instead.
I've never really used threading before in C# where I need to have two threads, as well as the main UI thread. Basically, I have the following.
public void StartTheActions()
{
// Starting thread 1....
Thread t1 = new Thread(new ThreadStart(action1));
t1.Start();
// Now, I want for the main thread (which is calling `StartTheActions` method)
// to wait for `t1` to finish. I've created an event in `action1` for this.
// The I wish `t2` to start...
Thread t2 = new Thread(new ThreadStart(action2));
t2.Start();
}
So, essentially, how can I have a thread wait for another one to finish? What is the best way to do this?
I can see five options available:
1. Thread.Join
As with Mitch's answer. But this will block your UI thread, however you get a Timeout built in for you.
2. Use a WaitHandle
ManualResetEvent is a WaitHandle as jrista suggested.
One thing to note is if you want to wait for multiple threads: WaitHandle.WaitAll() won't work by default, as it needs an MTA thread. You can get around this by marking your Main() method with MTAThread - however this blocks your message pump and isn't recommended from what I've read.
3. Fire an event
See this page by Jon Skeet about events and multi-threading. It's possible that an event can become unsubcribed between the if and the EventName(this,EventArgs.Empty) - it's happened to me before.
(Hopefully these compile, I haven't tried)
public class Form1 : Form
{
int _count;
void ButtonClick(object sender, EventArgs e)
{
ThreadWorker worker = new ThreadWorker();
worker.ThreadDone += HandleThreadDone;
Thread thread1 = new Thread(worker.Run);
thread1.Start();
_count = 1;
}
void HandleThreadDone(object sender, EventArgs e)
{
// You should get the idea this is just an example
if (_count == 1)
{
ThreadWorker worker = new ThreadWorker();
worker.ThreadDone += HandleThreadDone;
Thread thread2 = new Thread(worker.Run);
thread2.Start();
_count++;
}
}
class ThreadWorker
{
public event EventHandler ThreadDone;
public void Run()
{
// Do a task
if (ThreadDone != null)
ThreadDone(this, EventArgs.Empty);
}
}
}
4. Use a delegate
public class Form1 : Form
{
int _count;
void ButtonClick(object sender, EventArgs e)
{
ThreadWorker worker = new ThreadWorker();
Thread thread1 = new Thread(worker.Run);
thread1.Start(HandleThreadDone);
_count = 1;
}
void HandleThreadDone()
{
// As before - just a simple example
if (_count == 1)
{
ThreadWorker worker = new ThreadWorker();
Thread thread2 = new Thread(worker.Run);
thread2.Start(HandleThreadDone);
_count++;
}
}
class ThreadWorker
{
// Switch to your favourite Action<T> or Func<T>
public void Run(object state)
{
// Do a task
Action completeAction = (Action)state;
completeAction.Invoke();
}
}
}
If you do use the _count method, it might be an idea (to be safe) to increment it using
Interlocked.Increment(ref _count)
I'd be interested to know the difference between using delegates and events for thread notification, the only difference I know are events are called synchronously.
5. Do it asynchronously instead
The answer to this question has a very clear description of your options with this method.
Delegate/Events on the wrong thread
The event/delegate way of doing things will mean your event handler method is on thread1/thread2 not the main UI thread, so you will need to switch back right at the top of the HandleThreadDone methods:
// Delegate example
if (InvokeRequired)
{
Invoke(new Action(HandleThreadDone));
return;
}
Add
t1.Join(); // Wait until thread t1 finishes
after you start it, but that won't accomplish much as it's essentialy the same result as running on the main thread!
I can highly recommended reading Joe Albahari's Threading in C# free e-book, if you want to gain an understanding of threading in .NET.
If using from .NET 4 this sample can help you:
class Program
{
static void Main(string[] args)
{
Task task1 = Task.Factory.StartNew(() => doStuff());
Task task2 = Task.Factory.StartNew(() => doStuff());
Task task3 = Task.Factory.StartNew(() => doStuff());
Task.WaitAll(task1, task2, task3);
Console.WriteLine("All threads complete");
}
static void doStuff()
{
// Do stuff here
}
}
From: Create multiple threads and wait all of them to complete
The previous two answers are great and will work for simple scenarios. There are other ways to synchronize threads, however. The following will also work:
public void StartTheActions()
{
ManualResetEvent syncEvent = new ManualResetEvent(false);
Thread t1 = new Thread(
() =>
{
// Do some work...
syncEvent.Set();
}
);
t1.Start();
Thread t2 = new Thread(
() =>
{
syncEvent.WaitOne();
// Do some work...
}
);
t2.Start();
}
ManualResetEvent is one of the various WaitHandle's that the .NET framework has to offer. They can provide much richer thread synchronization capabilities than the simple, but very common tools like lock()/Monitor, Thread.Join, etc.
They can also be used to synchronize more than two threads, allowing complex scenarios such as a 'master' thread that coordinates multiple 'child' threads, multiple concurrent processes that are dependent upon several stages of each other to be synchronized, etc.
You want the Thread.Join() method, or one of its overloads.
I would have your main thread pass a callback method to your first thread, and when it's done, it will invoke the callback method on the mainthread, which can launch the second thread. This keeps your main thread from hanging while its waiting for a Join or Waithandle. Passing methods as delegates is a useful thing to learn with C# anyway.
This implementation is a little different from #jrista's example based on ManualResetEvent as it shows how the various options are like a red or green traffic light.
public System.Threading.AutoResetEvent thread1done = new System.Threading.AutoResetEvent(false);
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
{
thread1done.Set(); //set traffic light to green before threading
StartTheActions();
}
public void StartTheActions()
{
Thread t1 = new Thread(action1);
t1.Start();
thread1done.WaitOne(); //traffic light is red, until thread1done.Set inside action1()
Thread t2 = new Thread(action2);
t2.Start();
}
public void action1()
{
Thread.Sleep(5000);
//.... do some work
thread1done.Set(); //work is done, set traffic light to green at thread1done.WaitOne()
}
public void action2()
{
MessageBox.Show("Now processing action2");
}
Try this:
List<Thread> myThreads = new List<Thread>();
foreach (Thread curThread in myThreads)
{
curThread.Start();
}
foreach (Thread curThread in myThreads)
{
curThread.Join();
}
When I want the UI to be able to update its display while waiting for a task to complete, I use a while-loop that tests IsAlive on the thread:
Thread t = new Thread(() => someMethod(parameters));
t.Start();
while (t.IsAlive)
{
Thread.Sleep(500);
Application.DoEvents();
}
I took a little different approach. There is a counter option in previous answers, and I just applied it a bit differently. I was spinning off numerous threads and incremented a counter and decremented a counter as a thread started and stopped. Then in the main method I wanted to pause and wait for threads to complete I did.
while (threadCounter > 0)
{
Thread.Sleep(500); // Make it pause for half second so that we don’t spin the CPU out of control.
}
This is documented in my blog post: http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/
Another method is using lock(someObject) and Monitor.Wait(someObject[,timeout]) in one thread and lock(someObject) and Monitor.Pulse(someObject) in another thread. SomeObject has to be the same instance of a class in all 4 calls. SomeObject can't be a struct.
The first thread locks someObject and then calls Monitor.Wait() which releases the lock, so the second thread can lock someObject. When the second thread is finished it calls Monitor.Pulse(), and then the first thread's Monitor.Wait() ends.
Example: someObject is a queue, the first threads waits for the second to put an object in the queue and then dequeues that object.