How to Initialize the Task Object? - c#

This question is trivial and it is for readability. I would just like to know weather the following line of code has any alternative ? Is that code is correct in the means of Readability and style?
Task newTask = new Task(() => { });
EDIT:
This task will be created when certain condition/rule met. In that case i would assign an Action to this class.
if(condition Met && newTask.Status != TaskStatus.Running )
{
newTask = Task.Factory.StartNew(Action);
}
Thanks

A Task object is not mean to be run multiple times and started and stopped at will. If you cancel a task or it runs to completion you are meant to create a new Task object the next time you want to execute it again. You can keep a reference to your task object and cancel it using a CancellationTokenSource.
I would suggest simply keeping track of whether the task is running by either a bool variable or a Task variable itself where a null value indicates the task isn't running. For example:
private CancellationTokenSource _tokenSource = new CancellationTokenSource();
private Task _task;
public void StartDoingSomething()
{
if (_task == null)
{
_task = Task.Factory.StartNew(Worker, _tokenSource.Token)
.ContinueWith(_ => _task = null);
}
}
public void StopDoingSomething()
{
if (_task != null)
{
_tokenSource.Cancel();
}
}
private void Worker()
{
while (!_tokenSource.IsCancellationRequested)
{
// Do some unit of work
}
}

Related

Task counter C#, Interlocked

I would like to run tasks in parallel, with no more than 10 instances running at a given time.
This is the code I have so far:
private void Listen()
{
while (true)
{
var context = listener.GetContext();
var task = Task.Run(() => HandleContextAsync(context));
Interlocked.Increment(ref countTask);
if (countTask > 10)
{
//I save tasks in the collection
}
else
{
task.ContinueWith(delegate { Interlocked.Decrement(ref countTask); }); //I accomplish the task and reduce the counter
}
}
}
I would suggest that you use a Parallel loop; for example:
Parallel.For(1, 10, a =>
{
var context = listener.GetContext();
...
});
That will start a defined number of tasks without you needing to manage the process yourself.
If you want to continually execute code in parallel, with up to 10 instances at a time, this may be worth considering:
private void Listen()
{
var options = new ParallelOptions() { MaxDegreeOfParallelism = 10 };
Parallel.For(1, long.MaxValue - 1, options, (i) =>
{
var context = listener.GetContext();
HandleContextAsync(context);
});
}
Basically, it will run the code continually (well roughly long.MaxValue times). MaxDegreeOfParallelism ensures that it runs only 10 'instances' of the code at a time.
I'm assuming that the result from GetContext is not created by you, so, its probably not useful to use a Parallel.For when you don't know how many times to run or don't have all the contexts to handle right away.
So, probably the best way to resolve this would be by implementing your own TaskScheduler. This way you can add more tasks to be resolved on demand with a fixed concurrency level.
Based on the example from Microsoft Docs website you can already achieve this.
I made an example program with some changes to the LimitedConcurrencyLevelTaskScheduler from the website.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace parallel
{
class Program
{
private static Random Rand = new Random();
static void Main(string[] args)
{
var ts = new LimitedConcurrencyLevelTaskScheduler(10);
var taskFactory = new TaskFactory(ts);
while (true)
{
var context = GetContext(ts);
if (context.Equals("Q", StringComparison.OrdinalIgnoreCase))
break;
taskFactory.StartNew(() => HandleContextAsync(context));
}
Console.WriteLine("Waiting...");
while (ts.CountRunning != 0)
{
Console.WriteLine("Now running {0}x tasks with {1}x queued.", ts.CountRunning, ts.CountQueued);
Thread.Yield();
Thread.Sleep(100);
}
}
private static void HandleContextAsync(string context)
{
// delays for 1-10 seconds to make the example easier to understand
Thread.Sleep(Rand.Next(1000, 10000));
Console.WriteLine("Context: {0}, from thread: {1}", context, Thread.CurrentThread.ManagedThreadId);
}
private static string GetContext(LimitedConcurrencyLevelTaskScheduler ts)
{
Console.WriteLine("Now running {0}x tasks with {1}x queued.", ts.CountRunning, ts.CountQueued);
return Console.ReadLine();
}
}
// Provides a task scheduler that ensures a maximum concurrency level while
// running on top of the thread pool.
public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
{
// Indicates whether the current thread is processing work items.
[ThreadStatic]
private static bool _currentThreadIsProcessingItems;
// The list of tasks to be executed
private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
public int CountRunning => _nowRunning;
public int CountQueued
{
get
{
lock (_tasks)
{
return _tasks.Count;
}
}
}
// The maximum concurrency level allowed by this scheduler.
private readonly int _maxDegreeOfParallelism;
// Indicates whether the scheduler is currently processing work items.
private volatile int _delegatesQueuedOrRunning = 0;
private volatile int _nowRunning;
// Creates a new instance with the specified degree of parallelism.
public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
{
if (maxDegreeOfParallelism < 1)
throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
_maxDegreeOfParallelism = maxDegreeOfParallelism;
}
// Queues a task to the scheduler.
protected sealed override void QueueTask(Task task)
{
// Add the task to the list of tasks to be processed. If there aren't enough
// delegates currently queued or running to process tasks, schedule another.
lock (_tasks)
{
_tasks.AddLast(task);
if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
{
Interlocked.Increment(ref _delegatesQueuedOrRunning);
NotifyThreadPoolOfPendingWork();
}
}
}
// Inform the ThreadPool that there's work to be executed for this scheduler.
private void NotifyThreadPoolOfPendingWork()
{
ThreadPool.UnsafeQueueUserWorkItem(_ =>
{
// Note that the current thread is now processing work items.
// This is necessary to enable inlining of tasks into this thread.
_currentThreadIsProcessingItems = true;
try
{
// Process all available items in the queue.
while (true)
{
Task item;
lock (_tasks)
{
// When there are no more items to be processed,
// note that we're done processing, and get out.
if (_tasks.Count == 0)
{
Interlocked.Decrement(ref _delegatesQueuedOrRunning);
break;
}
// Get the next item from the queue
item = _tasks.First.Value;
_tasks.RemoveFirst();
}
// Execute the task we pulled out of the queue
Interlocked.Increment(ref _nowRunning);
if (base.TryExecuteTask(item))
Interlocked.Decrement(ref _nowRunning);
}
}
// We're done processing items on the current thread
finally { _currentThreadIsProcessingItems = false; }
}, null);
}
// Attempts to execute the specified task on the current thread.
protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// If this thread isn't already processing a task, we don't support inlining
if (!_currentThreadIsProcessingItems) return false;
// If the task was previously queued, remove it from the queue
if (taskWasPreviouslyQueued)
// Try to run the task.
if (TryDequeue(task))
return base.TryExecuteTask(task);
else
return false;
else
return base.TryExecuteTask(task);
}
// Attempt to remove a previously scheduled task from the scheduler.
protected sealed override bool TryDequeue(Task task)
{
lock (_tasks) return _tasks.Remove(task);
}
// Gets the maximum concurrency level supported by this scheduler.
public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }
// Gets an enumerable of the tasks currently scheduled on this scheduler.
protected sealed override IEnumerable<Task> GetScheduledTasks()
{
bool lockTaken = false;
try
{
Monitor.TryEnter(_tasks, ref lockTaken);
if (lockTaken) return _tasks;
else throw new NotSupportedException();
}
finally
{
if (lockTaken) Monitor.Exit(_tasks);
}
}
}
}

How to wait if the first code is under execution?

I have a situation where a user creates the instance of a class when the user clicks on a tabitem. This class contains a function which plots a graph and it's very time consuming so it is written async.
Now the problem is lets say the user first time click on tab and the class instantiates and the long process works for long time and meanwhile where the previous async task is not finshed and the user clicked again on the same tabitem.
In this situation i must wait until the previous async task is not finished and then on second click to tabitem must create instance after teh fist async task is finshed (It should wait until the first async process is not finshed).
The code is here:
if (selectedTabIndex == 2) //What is the user selected second time whil the previous task is still not finshed ?
{
DrawGraph obj= new DrawGraph(selectedItem.Name);
}
Somewhere in DrawGraph class constructor i have done:
public DrawGraph(string Name)
{
timeConsumingProcess(Name);
}
public async void timeConsumingProcess(string Name)
{
await startTaimeConsumingProcess();
}
What i want is when user clicks the second time this tab item number=2 then it must wait until the previous async task to finsh and then it must instantiate again DrawGraph class to
restart async again.
How to achieve it ?
In this situation i must wait until the previous async task is not finished and then on second click to tabitem must create instance after teh fist async task is finshed
Then have your code (a)wait on the last task:
private Task drawGraph = null;
...
if (selectedTabIndex == 2)
{
if (drawGraph != null)
await drawGraph;
DrawGraph obj = new DrawGraph(selectedItem.Name);
drawGraph = obj.timeConsumingProcess();
}
...
private readonly string name;
public DrawGraph(string Name)
{
name = Name;
}
public async Task timeConsumingProcess()
{
await startTaimeConsumingProcess();
}
Note that this requires you to use async Task instead of async void, which is good anyway because you should avoid async void.
You can store the Task representing the long running action in an instance variable in the form and use this to check whether the task is still running.
private Task drawGraphTask = null;
private void button1_Click(object sender, EventArgs e)
{
DrawGraph();
}
private async void DrawGraph()
{
// Only perform task when this is the first time
// or the previous task is already completed
if (drawGraphTask == null || drawGraphTask.IsCompleted)
{
drawGraphTask = startTimeConsumingProcess();
await drawGraphTask;
}
else
{
MessageBox.Show("Task already active");
}
}
private Task startTimeConsumingProcess()
{
// Your Code here
return Task.Delay(5000);
}
It is not good to start an asynchronous activity from inside a constructor. Move the asynchronous logic outside the DrawGraph class and make instantiating the class asynchronous at the level of the form already.
If it is a very time consuming process, you can choose to do it in a different thread
public DrawGraph(string Name)
{
var task = new Task(() => timeConsumingProcess(Name));
task.Start();
}
This way your main thread won't be blocked. If you want to run some code after this long running task is finished, use the ContinueWith method.
public DrawGraph(string Name)
{
_canPressTab = false;
var task = new Task(() => timeConsumingProcess(Name));
task.Start();
task.ContinueWith(t => {
_canPressTab = true;
...
});
}
UPDATE BELOW
As seen here, you can call the Draw method when you click on a tab. This checks if a task is already running. If not, it starts the task. If the task is running it will wait on it for it to complete and then start a new task.
public Task task = new Task(DoSomething);
private static void DoSomething()
{
Thread.Sleep(10000);
}
private void Draw()
{
//if tab is clicked run the Draw method
if (task.Status.Equals(TaskStatus.Running))
{
task.Wait();
task = new Task(DoSomething);
task.Start();
}
else if (task.Status.Equals(TaskStatus.RanToCompletion))
{
task = new Task(DoSomething);
task.Start();
}
else
{
task.Start();
}
}
A simple change will achieve this
public async Task DrawGraph(string Name)
{
await timeConsumingProcess(Name);
}
public async Task timeConsumingProcess(string Name)
{
await startTaimeConsumingProcess();
}
I made DrawGraph() return a Task as well in case you need to await it.

Create And Execute Tasks in A Row

I am developing an application in which i want to execute the tasks from only 1 place so that every time i add new Task it is added to that row to be executed, Also i want a priority for each task so if i set the task priority to HIGH it is added to the top of the row so it is executed immediately, On the other hand if i set the priority to Low it is added to the end of the row and so on...
I thought about using Tasks and ContinueWith but i don't have any clue from where should i start to have a class that totally handles my needs.
I am sorry for not providing a code or something bug i hope someone can get the point that i am pointing to and help me. And thank you in advance .
Well, if you didn't need to make room for high-priority tasks, you could make a simple helper class using Task and ContinueWith:
public class SimpleWorkQueue
{
private Task _main = null;
public void AddTask(Action task)
{
if (_main == null)
{
_main = new Task(task);
_main.Start();
}
else
{
Action<Task> next = (t) => task();
_main = _main.ContinueWith(next);
}
}
}
If you do need high-priority tasks, you probably need to handle more stuff yourself. Here is a producer/consumer example where all incoming tasks are inserted into a list in AddTask(), and a single worker thread consumes tasks from that list:
public class PrioritizedWorkQueue
{
List<Action> _queuedWork;
object _queueLocker;
Thread _workerThread;
public PrioritizedWorkQueue()
{
_queueLocker = new object();
_queuedWork = new List<Action>();
_workerThread = new Thread(LookForWork);
_workerThread.IsBackground = true;
_workerThread.Start();
}
private void LookForWork()
{
while (true)
{
Action work;
lock (_queueLocker)
{
while (!_queuedWork.Any()) { Monitor.Wait(_queueLocker); }
work = _queuedWork.First();
_queuedWork.RemoveAt(0);
}
work();
}
}
public void AddTask(Action task, bool highPriority)
{
lock (_queueLocker)
{
if (highPriority)
{
_queuedWork.Insert(0, task);
}
else
{
_queuedWork.Add(task);
}
Monitor.Pulse(_queueLocker);
}
}
}

Write an Async method that will await a bool

I would like to write a method that will await for a variable to be set to true.
Here is the psudo code.
bool IsSomethingLoading = false
SomeData TheData;
public async Task<SomeData> GetTheData()
{
await IsSomethingLoading == true;
return TheData;
}
TheData will be set by a Prism Event along with the IsSomethingLoading variable.
I have a call to the GetTheData method, but I would like it to run async (right now it just returns null if the data is not ready. (That leads to other problems.)
Is there a way to do this?
In many situations like this what you need is a TaskCompletionSource.
You likely have a method that is able to generate the data at some point in time, but it doesn't use a task to do it. Perhaps there is a method that takes a callback which provides the result, or an event that is fired to indicate that there is a result, or simply code using a Thread or ThreadPool that you are not inclined to re-factor into using Task.Run.
public Task<SomeData> GetTheData()
{
TaskCompletionSource<SomeData> tcs = new TaskCompletionSource<SomeData>();
SomeObject worker = new SomeObject();
worker.WorkCompleted += result => tcs.SetResult(result);
worker.DoWork();
return tcs.Task;
}
While you may need/want to provide the TaskCompletionSource to the worker, or some other class, or in some other way expose it to a broader scope, I've found it's often not needed, even though it's a very powerful option when it's appropriate.
It's also possible that you can use Task.FromAsync to create a task based on an asynchronous operation and then either return that task directly, or await it in your code.
You could use a TaskCompletionSource as your signal, and await that:
TaskCompletionSource<bool> IsSomethingLoading = new TaskCompletionSource<bool>();
SomeData TheData;
public async Task<SomeData> GetTheData()
{
await IsSomethingLoading.Task;
return TheData;
}
And in your Prism event do:
IsSomethingLoading.SetResult(true);
This work for me:
while (IsLoading) await Task.Delay(100);
I propose a very simple solution but not the best to answer the original question, if you are not regarding at speed performance :
...
public volatile bool IsSomethingLoading = false;
...
public async Task<SomeData> GetTheData()
{
// Launch the task asynchronously without waiting the end
_ = Task.Factory.StartNew(() =>
{
// Get the data from elsewhere ...
});
// Wait the flag
await Task.Factory.StartNew(() =>
{
while (IsSomethingLoading)
{
Thread.Sleep(100);
}
});
return TheData;
}
Important note : #Theodor Zoulias proposed : IsSomethingLoading shall be declared with volatile keyword, to avoid compiler optimizations and potential multithread issues when accessing from other threads.
For further information about compilator omptimizations follow this article :
The C# Memory Model in Theory and Practice
I'm adding a full test code below :
XAML :
<Label x:Name="label1" Content="Label" HorizontalAlignment="Left" Margin="111,93,0,0" VerticalAlignment="Top" Grid.ColumnSpan="2" Height="48" Width="312"/>
Test Code :
public partial class MainWindow : Window
{
// volatile keyword shall be used to avoid compiler optimizations
// and potential multithread issues when accessing IsSomethingLoading
// from other threads.
private volatile bool IsSomethingLoading = false;
public MainWindow()
{
InitializeComponent();
_ = TestASyncTask();
}
private async Task<bool> TestASyncTask()
{
IsSomethingLoading = true;
label1.Content = "Doing background task";
// Launch the task asynchronously without waiting the end
_ = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
IsSomethingLoading = false;
Thread.Sleep(5000);
HostController.Host.Invoke(new Action(() => label1.Content = "Background task terminated"));
});
label1.Content = "Waiting IsSomethingLoading ...";
// Wait the flag
await Task.Run(async () => { while (IsSomethingLoading) { await Task.Delay(100); }});
label1.Content = "Wait Finished";
return true;
}
}
/// <summary>
/// Main UI thread host controller dispatcher
/// </summary>
public static class HostController
{
/// <summary>
/// Main Host
/// </summary>
private static Dispatcher _host;
public static Dispatcher Host
{
get
{
if (_host == null)
{
if (Application.Current != null)
_host = Application.Current.Dispatcher;
else
_host = Dispatcher.CurrentDispatcher;
}
return _host;
}
}
}

c# asynchronously call method

There is this class unit that has a property bool status that marks whether a method, request, should be called on the unit. I have my other class, and in it, there is a method that should call request. To avoid blocking the main thread, I want to call the method asynchronously. The problem is that there isn't an event for the status change, and I don't want to make my asynchronous call do ugly stuff like:
while(!status){}unit.request(args);
or
while(!status){Thread.Sleep(100)}unit.request(args);
especially when I do not know the timescale in which status turns true.
How do I do this?
update: i forgot to mention that i cannot change unit. sorry for that.
You want to call a function (be it asynchronously or not) when a property changes. You have two choices:
Attach to an even that is signalled when the property changes
Periodically check the value of the property
You can't do the first, so you must do the second.
This is a sample of how you can manage this using an event.
Suppose this is your class
public class Unit
{
private readonly object _syncRoot = new object();
private bool _status;
public event EventHandler OnChanged;
public bool Status
{
get
{
lock (_syncRoot)
{
return _status;
}
}
set
{
lock (_syncRoot)
{
_status = value;
if (_status && OnChanged != null)
{
OnChanged.Invoke(this, null);
}
}
}
}
public void Process()
{
Thread.Sleep(1000);
Status = true;
}
}
Here is how you can use it
class Program
{
static void Main(string[] args)
{
var unit = new Unit();
unit.OnChanged += Unit_OnChanged;
Console.WriteLine("Before");
Task.Factory.StartNew(unit.Process);
Console.WriteLine("After");
Console.WriteLine("Manual blocking, or else app dies");
Console.ReadLine();
}
static void Unit_OnChanged(object sender, EventArgs e)
{
//Do your processing here
Console.WriteLine("Unit_OnChanged before");
Task.Factory.StartNew(()=>
{
Thread.Sleep(1000);
Console.WriteLine("Unit_OnChanged finished");
});
Console.WriteLine("Unit_OnChanged after");
}
}
This outputs
Before
After
Manual blocking, or else app dies
Unit_OnChanged before
Unit_OnChanged after
Unit_OnChanged finished
This is the classic polling problem, and there really isn't an elegant solution when polling is concerned. But we can work some functional programming in to get something which isn't a nightmare to use.
public static CancellationTokenSource Poll(
Func<bool> termination,
Action<CancellationToken> onexit,
int waitTime = 0,
int pollInterval = 1000)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
Action dispose = cts.Cancel;
var timer = new Timer(_ =>
{
if (termination() || token.IsCancellationRequested)
{
onexit(token);
dispose();
}
}, null, waitTime, pollInterval);
dispose = timer.Dispose;
return cts;
}
Example:
var condition = false;
Poll(() => condition == true, ct => Console.WriteLine("Done!"));
Console.ReadLine();
condition = true;
Console.ReadLine();
Use a System.Threading.AutoResetEvent instead of a bool if possible:
AutoResetEvent status = new AutoResetEvent();
In your asynchronous method, wait for it:
status.WaitOne();
unit.request(args);
Then, to signal it in your other class, call Set:
status.Set();

Categories

Resources