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.
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.
Let's say I have 10 tasks which should run simultaneously visualizing their progress using GUI. For simplicity let them be just counters 1 to 100. Main app should be console application. GUI controls should be generated on the fly.
Here's the code I've written:
static void Main(string[] args)
{
Enumerable.Range(0, 10).ToList().ForEach(x =>
frm.Controls.Add(new Label()
{
Left = 10,
Top = 22 * x,
}));
Thread mThread = new Thread(delegate ()
{
frm.ShowDialog();
});
mThread.SetApartmentState(ApartmentState.STA);
mThread.Start();
Jobs();
}
static void Jobs()
{
Task[] tasks = new Task[10];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = PayLoad(i);
}
Task.WaitAll(tasks);
}
static async Task PayLoad(int taskNumber)
{
Console.WriteLine($"Task {taskNumber} is starting...");
//await Task.Delay(1000);
for (int i = 1; i < 100; i++)
{
Console.WriteLine($"Task {taskNumber} - iteration {i} ");
Action act = delegate () { frm.Controls[taskNumber].Text = i.ToString(); };
frm.BeginInvoke(act);
await Task.Delay(1000);
}
}
The problem is the progress stops when all counters reach 1. If I comment the 2nd await the code completes but I can see it works synchronously. All the labels are filled one by one.
Am I missing something?
I need to start tasks in parallel, but I choose to use Task.Run instead of Parallel.Foreach, so I can get some feedback when all tasks finished and enable UI controls.
private async void buttonStart_Click(object sender, EventArgs e)
{
var cells = objectListView.CheckedObjects;
if(cells != null)
{
List<Task> tasks = new List<Task>();
foreach (Cell c in cells)
{
Cell cell = c;
var progressHandler = new Progress<string>(value =>
{
cell.Status = value;
});
var progress = progressHandler as IProgress<string>;
Task t = Task.Run(() =>
{
progress.Report("Starting...");
int a = 123;
for (int i = 0; i < 200000; i++)
{
a = a + i;
Task.Delay(500).Wait();
}
progress.Report("Done");
});
tasks.Add(t);
}
await Task.WhenAll(tasks);
Console.WriteLine("Done, enabld UI controls");
}
}
So what I expect is that I see in UI "Starting..." almost instantly for all items. What I actually see is first 4 items are "Starting..." (I guess because all 4 CPU cores are used per thread), then each second or less new item is "Starting". I have total 37 items and it takes around 30 seconds for all items to start all tasks.
How can I make it as parallel as possible?
How can I make it as parallel as possible?
The part of inner for loop is simulating long running CPU-bound job, which I would like to start at the same time as much as possible.
It's already as parallel as possible. Starting 37 threads that all have CPU-bound work to do will not make it go any faster, since you're apparently running it on a 4-core machine. There are 4 cores, so only 4 threads can actually run at a time. The other 33 threads are going to be waiting while 4 are running. They would only appear to run simultaneously.
That said, if you really want to start up all those thread pool threads, you can do this by calling ThreadPool.SetMinThreads.
I need to start tasks in parallel, but I choose to use Task.Run instead of Parallel.Foreach, so I can get some feedback when all tasks finished and enable UI controls.
Since you have parallel work to do, you should use Parallel. If you want the nice resume-on-the-UI-thread behavior of await, then you can use a single await Task.Run, something like this:
private async void buttonStart_Click(object sender, EventArgs e)
{
var cells = objectListView.CheckedObjects;
if (cells == null)
return;
var workItems = cells.Select(c => new
{
Cell = c,
Progress = new Progress<string>(value => { c.Status = value; }),
}).ToList();
await Task.Run(() => Parallel.ForEach(workItems, item =>
{
var progress = item.Progress as IProgress<string>();
progress.Report("Starting...");
int a = 123;
for (int i = 0; i < 200000; i++)
{
a = a + i;
Thread.Sleep(500);
}
progress.Report("Done");
}));
Console.WriteLine("Done, enabld UI controls");
}
I'd say, it is as parallel as possible. If you have 4 cores, you can run 4 threads in parallel.
If you can do stuff while waiting for the "delay", have a look into asynchronous programming (where one thread can run multiple tasks "at once", because most of them are waiting for something).
EDIT: you can also run Parallel.ForEach in its own task and await that:
private async void buttonStart_Click(object sender, EventArgs e)
{
var cells = objectListView.CheckedObjects;
if(cells != null)
{
await Task.Run( () => Parallel.ForEach( cells, c => ... ) );
}
}
I think it relies on your taskcreation-options.
TaskCreationOptions.LongRunning
Here you can find further informations:
https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskcreationoptions(v=vs.110).aspx
But you have to know, that task uses a threadpool with a finite maximum amount of threads. You can use LongRunning to signal, that this task needs a long time and should not clog your pool. I thinks it's more complex to create a long-running task, because the scheduler may create a new thread.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TaskTest
{
internal class Program
{
private static void Main(string[] args)
{
var demo = new Program();
demo.SimulateClick();
Console.ReadLine();
}
public void SimulateClick()
{
buttonStart_Click(null, null);
}
private async void buttonStart_Click(object sender, EventArgs e)
{
var tasks = new List<Task>();
for (var i = 0; i < 36; i++)
{
var taskId = i;
var t = Task.Factory.StartNew((() =>
{
Console.WriteLine($"Starting Task ({taskId})");
for (var ii = 0; ii < 200000; ii++)
{
Task.Delay(TimeSpan.FromMilliseconds(500)).Wait();
var s1 = new string(' ', taskId);
var s2 = new string(' ', 36-taskId);
Console.WriteLine($"Updating Task {s1}X{s2} ({taskId})");
}
Console.Write($"Done ({taskId})");
}),TaskCreationOptions.LongRunning);
tasks.Add(t);
}
await Task.WhenAll(tasks);
Console.WriteLine("Done, enabld UI controls");
}
}
}
I have a windows service (written in C#) that use the task parallel library dll to perform some parallel tasks (5 tasks a time)
After the tasks are executed once I would like to repeat the same tasks on an on going basis (hourly). Call the QueuePeek method
Do I use a timer or a counter like I have setup in the code snippet below?
I am using a counter to set up the tasks, once I reach five I exit the loop, but I also use a .ContinueWith to decrement the counter, so my thought is that the counter value would be below 5 hence the loop would continue. But my ContinueWith seems to be executing on the main thread and the loop then exits.
The call to DecrementCounter using the ContinueWith does not seem to work
FYI : The Importer class is to load some libraries using MEF and do the work
This is my code sample:
private void QueuePeek()
{
var list = SetUpJobs();
while (taskCounter < 5)
{
int j = taskCounter;
Task task = null;
task = new Task(() =>
{
DoLoad(j);
});
taskCounter += 1;
tasks[j] = task;
task.ContinueWith((t) => DecrementTaskCounter());
task.Start();
ds.SetJobStatus(1);
}
if (taskCounter == 0)
Console.WriteLine("Completed all tasks.");
}
private void DoLoad(int i)
{
ILoader loader;
DataService.DataService ds = new DataService.DataService();
Dictionary<int, dynamic> results = ds.AssignRequest(i);
var data = results.Where(x => x.Key == 2).First();
int loaderId = (int)data.Value;
Importer imp = new Importer();
loader = imp.Run(GetLoaderType(loaderId));
LoaderProcessor lp = new LoaderProcessor(loader);
lp.ExecuteLoader();
}
private void DecrementTaskCounter()
{
Console.WriteLine(string.Format("Decrementing task counter with threadId: {0}",Thread.CurrentThread.ManagedThreadId) );
taskCounter--;
}
I see a few issues with your code that can potentially lead to some hard to track-down bugs. First, if using a counter that all of the tasks can potentially be reading and writing to at the same time, try using Interlocked. For example:
Interlocked.Increment(ref _taskCounter); // or Interlocked.Decrement(ref _taskCounter);
If I understand what you're trying to accomplish, I think what you want to do is to use a timer that you re-schedule after each group of tasks is finished.
public class Worker
{
private System.Threading.Timer _timer;
private int _timeUntilNextCall = 3600000;
public void Start()
{
_timer = new Timer(new TimerCallback(QueuePeek), null, 0, Timeout.Infinite);
}
private void QueuePeek(object state)
{
int numberOfTasks = 5;
Task[] tasks = new Task[numberOfTasks];
for(int i = 0; i < numberOfTasks; i++)
{
tasks[i] = new Task(() =>
{
DoLoad();
});
tasks[i].Start();
}
// When all tasks are complete, set to run this method again in x milliseconds
Task.Factory.ContinueWhenAll(tasks, (t) => { _timer.Change(_timeUntilNextCall, Timeout.Infinite); });
}
private void DoLoad() { }
}
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