Consider the following code.
Thread
static void Main(string[] args)
{
Thread t = new Thread(Foo);
t.Start();
Console.WriteLine("Main ends.");
//t.Join();
}
static void Foo()
{
for (int x = 0; x < 1000000000; x++) ;
Console.WriteLine("Foo ends.");
}
Task
static void Main(string[] args)
{
Task t = new Task (Foo);
t.Start();
Console.WriteLine("Main ends.");
t.Wait();
}
static void Foo()
{
for (int x = 0; x < 1000000000; x++) ;
Console.WriteLine("Foo ends.");
}
When using Task, we need t.Wait() to wait for the thread pool thread to complete before the main thread ends but when using Thread, we don't need t.Join to get the same effect.
Question
Why is t.Join() not needed to prevent the main thread from ending before the other spawned threads end?
There are several differences, but the important part to answer your question is that the thread pool uses background threads, and these do not block the process from exiting. You can read more here.
t.wait() could not be used after a task is already started.
Related
we are running an ASP.NET 6 webapplication and are having strange issues with deadlocks.
The app suddenly freezes after some weeks of operations and it seems that it might be caused by our locking mechanism with the SemaphoreSlim class.
I tried to reproduce the issue with a simple test-project and found something strange.
The following code is simply starting 1000 tasks where each is doing some work (requesting semaphore-handle, waiting for 10 ms and releasing the semaphore).
I expected this code to simply execute one task after another. But it freezes because of a deadlock in the first call of the DoWork method (at await Task.Delay(10)).
Does anyone know why this causes a deadlock? I tried exactly the same code with ThreadPool.QueueUserWorkItem instead of Task.Run and Thread.Sleep instead of Task.Delay and this worked as expected. But as soon as I use the tasks it stops working.
Here is the complete code-snippet:
internal class Program
{
static int timeoutSec = 60;
static SemaphoreSlim semaphore = new SemaphoreSlim(1);
static int numPerIteration = 1000;
static int iteration = 0;
static int doneCounter = numPerIteration;
static int successCount = 0;
static int failedCount = 0;
static Stopwatch sw = new Stopwatch();
static Random rnd = new Random();
static void Main(string[] args)
{
Task.WaitAll(TestUsingTasks());
}
static async Task TestUsingTasks()
{
while (true)
{
var tasks = new List<Task>();
if (doneCounter >= numPerIteration)
{
doneCounter = 0;
if (iteration >= 1)
{
Log($"+++++ FINISHED TASK ITERATION {iteration} - SUCCESS: {successCount} - FAILURES: {failedCount} - Seconds: {sw.Elapsed.TotalSeconds:F1}", ConsoleColor.Magenta);
}
iteration++;
sw.Restart();
for (int i = 0; i < numPerIteration; i++)
{
// Start indepdent tasks to do some work
Task.Run(async () =>
{
if (await DoWork())
{
successCount++;
}
else
{
failedCount++;
}
doneCounter++;
});
}
}
await Task.Delay(10);
}
}
static async Task<bool> DoWork()
{
if (semaphore.Wait(timeoutSec * 1000)) // Request the semaphore to ensure that one 1 task at a time can enter
{
Log($"Got handle for {iteration} within {sw.Elapsed.TotalSeconds:F1}", ConsoleColor.Green);
var totalSec = sw.Elapsed.TotalSeconds;
await Task.Delay(10); // Wait for 10ms to simulate some work => Deadlock seems to happen here
Log($"RELEASING LOCK handle for {iteration} within {sw.Elapsed.TotalSeconds:F1}. WAIT took " + (sw.Elapsed.TotalSeconds - totalSec) + " seconds", ConsoleColor.Gray);
semaphore.Release();
return true;
}
else
{
Log($"ERROR: TASK handle failed for {iteration} within {sw.Elapsed.TotalSeconds:F1} sec", ConsoleColor.Red);
return false;
}
}
static void Log(string message, ConsoleColor color)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.White;
}
}
Thanks in advance!
But it freezes because of a deadlock in the first call of the DoWork method (at await Task.Delay(10)).
I would argue that it is not deadlock but a thread starvation issue. If you wait long enough you will see that threads will be able to finish the simulation wait from time to time.
The quick fix here is using non-blocking WaitAsync call with await:
static async Task<bool> DoWork()
{
if (await semaphore.WaitAsync(timeoutSec * 1000))
{
...
}
}
Also note:
It is recommended to wrap the code after Wait.. into try-finally block and release the semaphore in the finally.
Incrementing counters in parallel environments better should be done in atomic fashion, for example with Interlocked.Increment.
I have set StaTaskScheduler threads to 1 and I expected that I would get one Debug output every 5 seconds, but I end up with 10 with the same date
private void Test() {
for (int i = 0; i < 10; i++)
Task.Factory.StartNew(() =>
{
Task.Delay(5000); //temp for long operation
Debug.WriteLine(DateTime.Now);
}, CancellationToken.None, TaskCreationOptions.None, MainWindow.MyStaThread);
}
public static StaTaskScheduler MyStaThread =
new StaTaskScheduler(numberOfThreads: 1);
What am I missing? The reason for STA is that later it will be used for Icons extraction needing STA, but this test is to check it is done in sequence.
you have to start tasks using the MyStaThred.QueueTask rather then Task.Factory.Startnew:
private void Test() {
for (int i = 0; i < 10; i++)
MyStaThread.QueueTask(new Task(() =>
{
Task.Delay(5000); //temp for long operation
Debug.WriteLine(DateTime.Now);
}));
}
public static StaTaskScheduler MyStaThread =
new StaTaskScheduler(numberOfThreads: 1);
Task.Factory.Startnew uses .Net Framework internal thread pool and does not take the StaTaskScheduler into account.
When I run method by using Thread class, It didn't close immediately, It waits until second thread finish and then close ConsoleApp.
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting Main: {0}", Thread.CurrentThread.ManagedThreadId);
Thread thread = new Thread(Circle);
thread.Start();
Console.WriteLine("Ending Main: {0}", Thread.CurrentThread.ManagedThreadId);
}
static void Circle()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Working on Background thread: {0}", i);
Thread.Sleep(1000);
}
}
}
But, when I run same method with class Task, It close application immediately.
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting Main: {0}", Thread.CurrentThread.ManagedThreadId);
Task t = new Task(Circle);
t.Start();
Console.WriteLine("Ending Main: {0}", Thread.CurrentThread.ManagedThreadId);
}
static void Circle()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Working on Background thread: {0}", i);
Thread.Sleep(1000);
}
}
}
When you create a thread by default it is a foreground thread. An application waits for all foreground threads to exit before the application exists
When you create a Task this is run on a thread from the thread pool, which are background threads, therefore the application can exit even if the Task has not completed.
Edit
As pointed out in the comments, you should wait for a Task if you want the process not to exit until the Task finishes. You can also wait for background threads using Join so the behavior of a Task is similar to a background Thread with regard to process termination. You must explicitly wait for either of them or the process terminates.
say my main thread calls a loop which makes new threads and starts them on some other function.
for (int i = 0; i < numberOfThreads; i++)
{
Thread thread = new Thread(start);
thread.Start();
}
call_This_Function_After_All_Threads_Have_Completed_Execution();
How can i ensure that my method gets called only after all the other threads have completed execution.
You can use AutoResetEvent-s. Declare an AutoResetEvent array where all the threads can reach it.
AutoResetEvent[] events = new AutoResetEvent[numberOfThreads];
Start threads like this:
for (int i = 0; i < numberOfThreads; i++)
{
events[i] = new AutoResetEvent(false);
Thread thread = new Thread(start);
thread.Start(i);
}
WaitHandle.WaitAll(events);
call_This_Function_After_All_Threads_Have_Completed_Execution();
And finally don't forget to call the Set() method in the threads:
void start(object i)
{
//... do work
events[(int) i].Set();
}
I have three threads in my program and I want that when thread one finishes it signals thread 2 to start and when thread 2 finishes it should signal thread 3 to start.
How can I achieve this, I know there are wait handles to do that in C#, but I don't know how to use them ?
Following is the code of my program:
class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(Task1);
Thread t2 = new Thread(Task2);
Thread t3 = new Thread(Task3);
t1.Start();
t2.Start();
t3.Start();
Console.Read();
}
public static void Task1()
{
Console.WriteLine("I am assigned task 1:");
for (int i = 0; i < 50; i++)
{
Console.WriteLine("Task1" );
}
}
public static void Task2()
{
Console.WriteLine("I am assigned task 2:");
for (int i = 0; i < 50; i++)
{
Console.WriteLine("Task2");
}
}
public static void Task3()
{
Console.WriteLine("I am assigned task 3:");
for (int i = 0; i < 50; i++)
{
Console.WriteLine("Task3");
}
}
}
You need to pass events into the threaded functions that indicate what to signal when each one has finished and what to wait on before they run. Take a look at the (untested) code below to see what I mean:
class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(Task1);
ManualResetEvent e1=new ManualResetEvent(false);
Thread t2 = new Thread(Task2);
ManualResetEvent e2=new ManualResetEvent(false);
Thread t3 = new Thread(Task3);
ManualResetEvent e3=new ManualResetEvent(false);
t1.Start(()=>Task1(e1));
t2.Start(()=>Task2(e1,e2));
t3.Start(()=>Task3(e2,e3);
Console.Read();
t1.Join();
t2.Join();
t3.Join();
}
public static void Task1(EventWaitHandle handle)
{
Console.WriteLine("I am assigned task 1:");
for (int i = 0; i < 50; i++)
{
Console.WriteLine("Task1" );
}
handle.Set();
}
public static void Task2(EventWaitHandle waitFor, EventWaitHandle handle)
{
waitFor.WaitOne();
Console.WriteLine("I am assigned task 2:");
for (int i = 0; i < 50; i++)
{
Console.WriteLine("Task2");
}
handle.Set();
}
public static void Task3(EventWaitHandle waitFor, EventWaitHandle handle)
{
waitFor.WaitOne();
Console.WriteLine("I am assigned task 3:");
for (int i = 0; i < 50; i++)
{
Console.WriteLine("Task3");
}
handle.Set();
}
}
It appears that you want to run Tasks 1 - 3 to execute synchronously. So, you might as well do:
Task1();
Task2();
Task3();
If you want to offload the execution of these tasks to another thread, you can do:
static void RunTasks()
{
Task1();
Task2();
Task3();
}
static void Main()
{
new Thread(RunTasks).Start();
}
If you really wanted each task to run on a separate thread, and wait for the previous task to finish, you can use the Thread.Join method.
EDIT:
Since you really want to use wait-handles to accomplish this, take a look at the ManualResetEvent class.
Notifies one or more waiting threads
that an event has occurred.
Call the WaitOne method on it to wait on the event, and the Set method to signal it.
Example (horribly contrived code):
var afterT1Event = new ManualResetEvent(false);
var afterT2Event = new ManualResetEvent(false);
Thread t1 = new Thread(() => { Task1(); afterT1Event.Set(); });
Thread t2 = new Thread(() => { afterT1Event.WaitOne(); Task2(); afterT2Event.Set(); });
Thread t3 = new Thread(() => { afterT2Event.WaitOne(); Task3(); });
t1.Start();
t2.Start();
t3.Start();
If you want to use WaitHandles to acheive these then you could do the following:
declare the following two fields:
static ManualResetEvent handle1 = new ManualResetEvent(false);
static ManualResetEvent handle2 = new ManualResetEvent(false);
then at the end of Task1, add this:
handle1.Set();
at the beginning of Task2, add:
handle1.WaitOne();
then at the end, add
handle2.Set();
then finally at the beginning of Task3 add
handle2.WaitOne();
This feels very artificial, almost like homework...
... but basically you can use Join on a thread to wait for it.
Or the old msdn tutorial/example is very reasonable on this: http://msdn.microsoft.com/en-us/library/aa645740(VS.71).aspx
You could use ManualResetEvents and WaitHandle.WaitAny. Basically when one thread is done you would notify the other thread by using a ManualResetEvent (ManualResetEvent.Set()).
ManualResetEvent threadFinished = new ManualResetEvent(false);
//You would set this in the thread that has finished
threadFinished.Set()
//You would use this in the thread that you want to wait for this event to be signalled
int nWait = WaitHandle.WaitAny(new ManualResetEvent[] { threadFinished }, 10, true);
//if yes stop thread
if (nWait == 0)
{
//Thread is finished
}
i think using thread.join() will be more simpler any other solution