Using async socket in Tasks - c#

I have an application that is processing items in a FIFO queue using Tasks in .net 4.0.
I am new to TPL and Tasks in .net and was wondering if there is an easy solution to my problem:
The Action delegate in the Task is assigned to a method that is sending and receiving data on an asynchronous socket. The problem I am having is that the Task ends "prematurely". How do I tell the Task to wait until all communication is completed before processing the next item in the queue?
One solution is to switch to using a synchronous socket, but I was hoping there is a way to do this using the async socket.
EDIT
Added some code:
class Program
{
private BlockingCollection<string> myQueue;
private CancellationTokenSource cancellationSignalForConsumeTask;
private CancellationTokenSource cancellationSignalForProcessCommandTask;
private AsyncSocket mySocket;
public void Main(string[] args)
{
mySocket = new mySocket();
myscoket.ReceiveData += mySocket_ReceiveData;
cancellationSignalForConsumeTask = new CancellationTokenSource();
Task listenerTask = Task.Factory.StartNew((obj) => Consume(),
cancellationSignalForConsumeTask.Token,
TaskCreationOptions.LongRunning);
while (true)
{}
}
private void Consume()
{
while (!myQueue.IsCompleted )
{
string _item = myQueue.Take();
cancellationSignalForProcessCommandTask = new CancellationTokenSource();
Task t = new Task(() =>
{
cancellationSignalForProcessCommandTask.Token.ThrowIfCancellationRequested();
DoSomeWork(_item);
}, cancellationSignalForProcessCommandTask.Token, TaskCreationOptions.LongRunning);
t.Start();
t.Wait();
}
}
private void DoSomeWork(string _item)
{
mySocket.SendData("Data to server that could take a long time to process")
}
private void mySocket_ReceiveData(string dataFromServer)
{
string returnMessage = dataFromServer;
//I want the Task to end here...
}
}
The problem is that the Task ends when the DoSomeWork() method finishes (and I understand why), is there a way I can manually tell the Task to end through the CancellationTokenSource object maybe?

If I understand correctly, you want to wait on the task the receives the data, but you're currently waiting on the task that sends the data. One way to do so would be to use a construct like AutoResetEvent:
private AutoResetEvent autoResetEvent = new AutoResetEvent(false);
private void Consume()
{
while (!myQueue.IsCompleted )
{
string _item = myQueue.Take();
cancellationSignalForProcessCommandTask = new CancellationTokenSource();
Task t = new Task(() =>
{
cancellationSignalForProcessCommandTask.Token.ThrowIfCancellationRequested();
DoSomeWork(_item);
}, cancellationSignalForProcessCommandTask.Token, TaskCreationOptions.LongRunning);
t.Start();
// Wait for data to be received.
// This line will block until autoResetEvent.Set() is called.
autoResetEvent.WaitOne();
}
}
private void mySocket_ReceiveData(string dataFromServer)
{
string returnMessage = dataFromServer;
// Notify other threads that data was received and that processing can continue.
autoResetEvent.Set();
}
This is only an example of using AutoResetEvent - you'd probably want to refine it to suit your needs.

Related

CancellationTokenSource does not cancel the task

I have Two button for scenarios where one initiate the task and other stop that task.
// this is the property which is used to cancel the task
CancellationTokenSource cTokenSource;
private async void OnReadCommand()
{
cTokenSource = new CancellationTokenSource();
ReadAction();
}
private async void ReadAction()
{
Task.Factory.StartNew(() => {
while (true)
{
Task.Delay(TimeSpan.FromSeconds(2)).Wait();
//writing in debug console
Debug.WriteLine($"Some Random Nos : {Guid.NewGuid().ToString()}");
//sending it to the ui for testing
uiContext.Send(x => MessageArea2Content.Message = Guid.NewGuid().ToString(), null);
}
},cTokenSource.Token);
}
private async void OnCancelCommand()
{
// it's used to cancel the task
cTokenSource.Cancel();
}
my app is wpf and using mvvm pattern and prism library.
while calling the OnCancelCommand the task is running in background and printing the GUID.
I have to cancel the task only and only on OnCancelCommand.
You need to implement the code for exiting the loop yourself:
private async void ReadAction()
{
Task.Factory.StartNew(() => {
while (true)
{
Task.Delay(TimeSpan.FromSeconds(2)).Wait();
//writing in debug console
Debug.WriteLine($"Some Random Nos : {Guid.NewGuid().ToString()}");
//sending it to the ui for testing
uiContext.Send(x => MessageArea2Content.Message = Guid.NewGuid().ToString(), null);
cTokenSource.Token.ThrowIfCancellationRequested();
}
},cTokenSource.Token);
}
or
private async void ReadAction()
{
Task.Factory.StartNew(() => {
while (true)
{
Task.Delay(TimeSpan.FromSeconds(2)).Wait();
//writing in debug console
Debug.WriteLine($"Some Random Nos : {Guid.NewGuid().ToString()}");
//sending it to the ui for testing
uiContext.Send(x => MessageArea2Content.Message = Guid.NewGuid().ToString(), null);
if (cTokenSource.Token.IsCancellationRequested)
{
break; // or return;
}
}
},cTokenSource.Token);
Usage examples you can find in the documenation Task Class. The only benefit that you get from passing CancellationToken to StartNew method is that it can automatically cancel the task for you if the source is cancelled before the task started. However to cancel it during the run you need to code the logic yourself. Here is another good reading on that https://stackoverflow.com/questions/48312544/whats-the-benefit-of-passing-a-cancellationtoken-as-a-parameter-to-task-run#:~:text=In%20summary%2C%20providing%20the%20cancellation,to%20start%20running%20the%20task.
Furthermore, I would suggest to you using await in the logic that you execute in StartNew so that you do not loose the benefits of being asynchronous:
private async void ReadAction()
{
Task.Factory.StartNew(async () => {
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(2));
//writing in debug console
Debug.WriteLine($"Some Random Nos : {Guid.NewGuid().ToString()}");
//sending it to the ui for testing
uiContext.Send(x => MessageArea2Content.Message = Guid.NewGuid().ToString(), null);
if (cTokenSource.Token.IsCancellationRequested)
{
break; // or return;
}
}
},cTokenSource.Token)
That way threads will no longer get blocked and will be released during a call to Delay.

How to call async method in a thread but wait for it in c#

I have a thread which is responsible for calling a webapi from 4 websites exactly every 2 seconds. The Webapi call method should not be awaited because if a website is not available it will wait 5 second to get timeout and then the next website call will be delayed.
As HttpClient in .NET 4.7.2 has only async methods , it should be used with await, and if not , compiler gives warning and we may get unexpected behavior (as Microsoft says) .
So should I use Task.Run or call Threadpool.QueueUserWorkItem to make a webapi call in parallel.
Here is sudocode :
public class Test1
{
private AutoResetEvent waitEvent = new AutoResetEvent(false);
private volatile bool _terminated = false;
public void Start()
{
Thread T = new Thread(ProcThread);
T.Start();
}
private async void ProcThread()
{
while (!_terminated)
{
await CallWebApi(); <=========== this line
waitEvent.WaitOne(2000);
}
}
private async Task CallWebApi()
{
HttpClient client = new HttpClient();
.....
.....
}
}
So you have an async procedure that uses a HttpClient to fetch some information and process the fetched data:
async Task CallWebApiAsync() {...}
Improvement 1: it is good practice to suffix async methods with async. This is done to make it possible to let an async version exist next to a non-async version that does something similarly.
Inside this method you are using one of the HttpClient methods to fetch the information. As CallWebApiAsync is awaitable, I assume the async methods are used (GetAsync, GetStreamAsync, etc), and that the method only awaits when it needs the result of the async method.
The nice thing about this is, that as a user of CallWebApiAsync, as long as you don't await the call, you are free to do other things, even if the website isn't reacting. The problem is: after 2 seconds, you want to call the method again. But what to do if the method hasn't finished yet.
Improvement 2 Because you want to be able to start a new Task, while the previous one has not finished: remember the started tasks, and throw them away when finished.
HashSet<Task> activeTasks = new HashSet<Task>(); // efficient add, lookup, and removal
void TaskStarted(Task startedTask)
{
// remember the startedTask
activeTasks.Add(startedTask);
}
void TaskCompleted(Task completedTask)
{
// If desired: log or process the results
LogFinishedTask(completedTask);
// Remove the completedTask from the set of ActiveTasks:
activeTasks.Remove(completedTask);
}
It might be handy to remove all completed tasks at once:
void RemoveCompletedTasks()
{
var completedTasks = activeTasks.Where(task => task.IsCompleted).ToList();
foreach (var task in completedTasks)
{
TaskCompleted(completedTask);
}
}
Now we can adjust your ProcThread.
Improvement 3: in async-await always return Task instead of void and Task<TResult> instead of TResult. Only exception: eventhandlers return void.
async Task ProcThread()
{
// Repeatedly: start a task; remember it, and wait 2 seconds
TimeSpan waitTime = TimeSpan.FromSeconds(2);
while (!terminationRequested)
{
Task taskWebApi = CallWebApiAsync();
// You didn't await, so you are free to do other things
// Remember the task that you started.
this.TaskStarted(taskWebApi);
// wait a while before you start new task:
await Task.Delay(waitTime);
// before starting a new task, remove all completed tasks
this.RemoveCompletedTasks();
}
}
Improvement 4: Use TimeSpan.
TimeSpan.FromSeconds(2) is much easier to understand what it represents than a value 2000.
How to stop?
The problem is of course, after you request termination there might still be some tasks running. You'll have to wait for them to finish. But even then: some tasks might not finish at all within reasonable time.
Improvement 5: use CancellationToken to request cancellation.
To cancel tasks in a neat way, class CancellationToken is invented. Users who start a task create a CancellationTokenSource object, and ask this object for a CancellationToken. This token is passed to all async methods. As soon as the user wants to cancel all tasks that were started using this CancellationTokenSource, he requests the CancellationTokenSource to cancel.
All tasks that have a token from this source have promised to regularly check the token to see if cancellation is requested. If so, the task does some cleanup (if needed) and returns.
Everything summarized in one class:
class Test1
{
private HttpClient httpClient = new HttpClient(...);
private HashSet<TTask> activeTasks = new HashSet<TTask>();
public async Task StartAsync(CancellationToken cancellationToken)
{
// repeated CallWebApiAsync until cancellation is requested
TimeSpan waitTime = TimeSpan.FromSeconds(2);
// repeat the following until OperationCancelled
try
{
while (true))
{
// stop if cancellation requested
cancellationToken.ThrowIfCancellationRequested();
var taskWebApi = this.CallWebApiAsync(cancellationToken);
this.activeTasks.Add(taskWebApi);
await Task.Delay(waitTime, cancellationToken);
// remove all completed tasks:
activeTasks.RemoveWhere(task => task.IsCompleted);
}
}
catch (OperationCanceledException exception)
{
// caller requested to cancel. Wait until all tasks are finished.
await Task.WhenAll(this.activeTasks);
// if desired do some logging for all tasks that were not completed.
}
}
And the adjusted CallWebApiAsync:
private async Task CallWebApiAsync(CancellationToken cancellationToken)
{
const string requestUri = ...
var httpResponseMessage = await this.httpClient.GetAsync(requestUri, cancellationToken);
// if here: cancellation not requested
this.ProcessHttpResponse(httpResponseMessage);
}
private void ProcessHttpRespons(HttpResponseMessage httpResponseMessage)
{
...
}
}
Usage:
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Test1 test = new Test1();
Task taskCallWebApiRepeatedly = test.StartAsync(cancellationTokenSource.Token);
// because you didn't await, you are free to do other things, while WebApi is called
// every 2 seconds
DoSomethingElse();
// you get bored. Request cancellation:
cancellationTokenSource.Cancel();
// of course you need to await until all tasks are finished:
await Task.Wait(taskCallWebApiRepeatedly);
Because everyone promises to check regularly if cancellation is requested, you are certain that within reasonable time all tasks are finished, and have cleaned up their mess. The definition or "reasonable time" is arbitrary, but let's say, less than 100 msec?
If all you want is to execute a method every two seconds, then a System.Timers.Timer is probably the most suitable tool to use:
public class Test1
{
private readonly HttpClient _client;
private readonly System.Timers.Timer _timer;
public Test1()
{
_client = new HttpClient();
_timer = new System.Timers.Timer();
_timer.Interval = 2000;
_timer.Elapsed += Timer_Elapsed;
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
var fireAndForgetTask = CallWebApiAsync();
}
private async Task CallWebApiAsync()
{
var html = await _client.GetStringAsync("http://example.com");
//...
}
public void Start() => _timer.Start();
public void Stop() => _timer.Stop();
}
something like this. BTW take this as pseudo code as I am typing sitting on my bed:)
List<Task> tasks = new List<Task>();
tasks.Add(CallWebApi());
while (! await Task.WhenAny(tasks))
{
tasks.Add(CallWebApi()); <=========== this line
await Task.Delay(2000);
}

TaskContinuationOptions.RunContinuationsAsynchronously and Stack Dives

In this blog post, Stephan Toub describes a new feature that will be included in .NET 4.6 which adds another value to the TaskCreationOptions and TaskContinuationOptions enums called RunContinuationsAsynchronously.
He explains:
"I talked about a ramification of calling {Try}Set* methods on
TaskCompletionSource, that any synchronous continuations off
of the TaskCompletionSource’s Task could run synchronously as
part of the call. If we were to invoke SetResult here while holding
the lock, then synchronous continuations off of that Task would be run
while holding the lock, and that could lead to very real problems.
So, while holding the lock we grab the TaskCompletionSource to
be completed, but we don’t complete it yet, delaying doing so until
the lock has been released"
And gives the following example to demonstrate:
private SemaphoreSlim _gate = new SemaphoreSlim(1, 1);
private async Task WorkAsync()
{
await _gate.WaitAsync().ConfigureAwait(false);
try
{
// work here
}
finally { _gate.Release(); }
}
Now imagine that you have lots of calls to WorkAsync:
await Task.WhenAll(from i in Enumerable.Range(0, 10000) select WorkAsync());
We've just created 10,000 calls to WorkAsync that will be
appropriately serialized on the semaphore. One of the tasks will
enter the critical region, and the others will queue up on the
WaitAsync call, inside SemaphoreSlim effectively enqueueing the task
to be completed when someone calls Release. If Release completed that
Task synchronously, then when the first task calls Release, it'll
synchronously start executing the second task, and when it calls
Release, it'll synchronously start executing the third task, and so
on. If the "//work here" section of code above didn't include any
awaits that yielded, then we're potentially going to stack dive here
and eventually potentially blow out the stack.
I'm having a hard time grasping the part where he talks about executing the continuation synchronously.
Question
How could this possibly cause a stack dive? More so, And what is RunContinuationsAsynchronously effectively going to do in order to solve that problem?
The key concept here is that a task's continuation may run synchronously on the same thread that completed the antecedent task.
Let's imagine that this is SemaphoreSlim.Release's implementation (it's actually Toub's AsyncSemphore's):
public void Release()
{
TaskCompletionSource<bool> toRelease = null;
lock (m_waiters)
{
if (m_waiters.Count > 0)
toRelease = m_waiters.Dequeue();
else
++m_currentCount;
}
if (toRelease != null)
toRelease.SetResult(true);
}
We can see that it synchronously completes a task (using TaskCompletionSource).
In this case, if WorkAsync has no other asynchronous points (i.e. no awaits at all, or all awaits are on an already completed task) and calling _gate.Release() may complete a pending call to _gate.WaitAsync() synchronously on the same thread you may reach a state in which a single thread sequentially releases the semaphore, completes the next pending call, executes // work here and then releases the semaphore again etc. etc.
This means that the same thread goes deeper and deeper in the stack, hence stack dive.
RunContinuationsAsynchronously makes sure the continuation doesn't run synchronously and so the thread that releases the semaphore moves on and the continuation is scheduled for another thread (which one depends on the other continuation parameters e.g. TaskScheduler)
This logically resembles posting the completion to the ThreadPool:
public void Release()
{
TaskCompletionSource<bool> toRelease = null;
lock (m_waiters)
{
if (m_waiters.Count > 0)
toRelease = m_waiters.Dequeue();
else
++m_currentCount;
}
if (toRelease != null)
Task.Run(() => toRelease.SetResult(true));
}
How could this possibly cause a stack dive? More so, And what is
RunContinuationsAsynchronously effectively going to do in order to
solve that problem?
i3arnon provides a very good explanation of the reasons behind introducing RunContinuationsAsynchronously. My answer is rather orthogonal to his; in fact, I'm writing this for my own reference as well (I myself ain't gonna remember any subtleties of this in half a year from now :)
First of all, let's see how TaskCompletionSource's RunContinuationsAsynchronously option is different from Task.Run(() => tcs.SetResult(result)) or the likes. Let's try a simple console application:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplications
{
class Program
{
static void Main(string[] args)
{
ThreadPool.SetMinThreads(100, 100);
Console.WriteLine("start, " + new { System.Environment.CurrentManagedThreadId });
var tcs = new TaskCompletionSource<bool>();
// test ContinueWith-style continuations (TaskContinuationOptions.ExecuteSynchronously)
ContinueWith(1, tcs.Task);
ContinueWith(2, tcs.Task);
ContinueWith(3, tcs.Task);
// test await-style continuations
ContinueAsync(4, tcs.Task);
ContinueAsync(5, tcs.Task);
ContinueAsync(6, tcs.Task);
Task.Run(() =>
{
Console.WriteLine("before SetResult, " + new { System.Environment.CurrentManagedThreadId });
tcs.TrySetResult(true);
Thread.Sleep(10000);
});
Console.ReadLine();
}
// log
static void Continuation(int id)
{
Console.WriteLine(new { continuation = id, System.Environment.CurrentManagedThreadId });
Thread.Sleep(1000);
}
// await-style continuation
static async Task ContinueAsync(int id, Task task)
{
await task.ConfigureAwait(false);
Continuation(id);
}
// ContinueWith-style continuation
static Task ContinueWith(int id, Task task)
{
return task.ContinueWith(
t => Continuation(id),
CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
}
}
Note how all continuations run synchronously on the same thread where TrySetResult has been called:
start, { CurrentManagedThreadId = 1 }
before SetResult, { CurrentManagedThreadId = 3 }
{ continuation = 1, CurrentManagedThreadId = 3 }
{ continuation = 2, CurrentManagedThreadId = 3 }
{ continuation = 3, CurrentManagedThreadId = 3 }
{ continuation = 4, CurrentManagedThreadId = 3 }
{ continuation = 5, CurrentManagedThreadId = 3 }
{ continuation = 6, CurrentManagedThreadId = 3 }
Now what if we don't want this to happen, and we want each continuation to run asynchronously (i.e., in parallel with other continuations and possibly on another thread, in the absence of any synchronization context)?
There's a trick that could do it for await-style continuations, by installing a fake temporary synchronization context (more details here):
public static class TaskExt
{
class SimpleSynchronizationContext : SynchronizationContext
{
internal static readonly SimpleSynchronizationContext Instance = new SimpleSynchronizationContext();
};
public static void TrySetResult<TResult>(this TaskCompletionSource<TResult> #this, TResult result, bool asyncAwaitContinuations)
{
if (!asyncAwaitContinuations)
{
#this.TrySetResult(result);
return;
}
var sc = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(SimpleSynchronizationContext.Instance);
try
{
#this.TrySetResult(result);
}
finally
{
SynchronizationContext.SetSynchronizationContext(sc);
}
}
}
Now, using tcs.TrySetResult(true, asyncAwaitContinuations: true) in our test code:
start, { CurrentManagedThreadId = 1 }
before SetResult, { CurrentManagedThreadId = 3 }
{ continuation = 1, CurrentManagedThreadId = 3 }
{ continuation = 2, CurrentManagedThreadId = 3 }
{ continuation = 3, CurrentManagedThreadId = 3 }
{ continuation = 4, CurrentManagedThreadId = 4 }
{ continuation = 5, CurrentManagedThreadId = 5 }
{ continuation = 6, CurrentManagedThreadId = 6 }
Note how await continuations now run in parallel (albeit, still after all synchronous ContinueWith continuations).
This asyncAwaitContinuations: true logic is a hack and it works for await continuations only. The new RunContinuationsAsynchronously makes it work consistently for any kind of continuations, attached to TaskCompletionSource.Task.
Another nice aspect of RunContinuationsAsynchronously is that any await-style continuations scheduled to be resumed on specific synchronization context will run on that context asynchronously (using SynchronizationContext.Post, even if TCS.Task completes on the same context (unlike the current behavior of TCS.SetResult). ContinueWith-style continuations will be also be run asynchronously by their corresponding task schedulers (most often, TaskScheduler.Default or TaskScheduler.FromCurrentSynchronizationContext). They won't be inlined via TaskScheduler.TryExecuteTaskInline. I believe Stephen Toub has clarified that in the comments to his blog post, and it also can be seen here in CoreCLR's Task.cs.
Why should we be worrying about imposing asynchrony on all continuations?
I usually need it when I deal with async methods which execute cooperatively (co-routines).
A simple example is a pause-able asynchronous processing: one async process pauses/resumes the execution of another. Their execution workflow synchronizes at certain await points, and TaskCompletionSource is used for such kind of synchronization, directly or indirectly.
Below is some ready-to-play-with sample code which uses an adaptation of Stephen Toub's PauseTokenSource. Here, one async method StartAndControlWorkAsync starts and periodically pauses/resumes another async method, DoWorkAsync. Try changing asyncAwaitContinuations: true to asyncAwaitContinuations: false and see the logic being completely broken:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static void Main()
{
StartAndControlWorkAsync(CancellationToken.None).Wait();
}
// Do some work which can be paused/resumed
public static async Task DoWorkAsync(PauseToken pause, CancellationToken token)
{
try
{
var step = 0;
while (true)
{
token.ThrowIfCancellationRequested();
Console.WriteLine("Working, step: " + step++);
await Task.Delay(1000).ConfigureAwait(false);
Console.WriteLine("Before await pause.WaitForResumeAsync()");
await pause.WaitForResumeAsync();
Console.WriteLine("After await pause.WaitForResumeAsync()");
}
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e);
throw;
}
}
// Start DoWorkAsync and pause/resume it
static async Task StartAndControlWorkAsync(CancellationToken token)
{
var pts = new PauseTokenSource();
var task = DoWorkAsync(pts.Token, token);
while (true)
{
token.ThrowIfCancellationRequested();
Console.WriteLine("Press enter to pause...");
Console.ReadLine();
Console.WriteLine("Before pause requested");
await pts.PauseAsync();
Console.WriteLine("After pause requested, paused: " + pts.IsPaused);
Console.WriteLine("Press enter to resume...");
Console.ReadLine();
Console.WriteLine("Before resume");
pts.Resume();
Console.WriteLine("After resume");
}
}
// Based on Stephen Toub's PauseTokenSource
// http://blogs.msdn.com/b/pfxteam/archive/2013/01/13/cooperatively-pausing-async-methods.aspx
// the main difference is to make sure that when the consumer-side code - which requested the pause - continues,
// the producer-side code has already reached the paused (awaiting) state.
// E.g. a media player "Pause" button is clicked, gets disabled, playback stops,
// and only then "Resume" button gets enabled
public class PauseTokenSource
{
internal static readonly Task s_completedTask = Task.Delay(0);
readonly object _lock = new Object();
bool _paused = false;
TaskCompletionSource<bool> _pauseResponseTcs;
TaskCompletionSource<bool> _resumeRequestTcs;
public PauseToken Token { get { return new PauseToken(this); } }
public bool IsPaused
{
get
{
lock (_lock)
return _paused;
}
}
// request a resume
public void Resume()
{
TaskCompletionSource<bool> resumeRequestTcs = null;
lock (_lock)
{
resumeRequestTcs = _resumeRequestTcs;
_resumeRequestTcs = null;
if (!_paused)
return;
_paused = false;
}
if (resumeRequestTcs != null)
resumeRequestTcs.TrySetResult(true, asyncAwaitContinuations: true);
}
// request a pause (completes when paused state confirmed)
public Task PauseAsync()
{
Task responseTask = null;
lock (_lock)
{
if (_paused)
return _pauseResponseTcs.Task;
_paused = true;
_pauseResponseTcs = new TaskCompletionSource<bool>();
responseTask = _pauseResponseTcs.Task;
_resumeRequestTcs = null;
}
return responseTask;
}
// wait for resume request
internal Task WaitForResumeAsync()
{
Task resumeTask = s_completedTask;
TaskCompletionSource<bool> pauseResponseTcs = null;
lock (_lock)
{
if (!_paused)
return s_completedTask;
_resumeRequestTcs = new TaskCompletionSource<bool>();
resumeTask = _resumeRequestTcs.Task;
pauseResponseTcs = _pauseResponseTcs;
_pauseResponseTcs = null;
}
if (pauseResponseTcs != null)
pauseResponseTcs.TrySetResult(true, asyncAwaitContinuations: true);
return resumeTask;
}
}
// consumer side
public struct PauseToken
{
readonly PauseTokenSource _source;
public PauseToken(PauseTokenSource source) { _source = source; }
public bool IsPaused { get { return _source != null && _source.IsPaused; } }
public Task WaitForResumeAsync()
{
return IsPaused ?
_source.WaitForResumeAsync() :
PauseTokenSource.s_completedTask;
}
}
}
public static class TaskExt
{
class SimpleSynchronizationContext : SynchronizationContext
{
internal static readonly SimpleSynchronizationContext Instance = new SimpleSynchronizationContext();
};
public static void TrySetResult<TResult>(this TaskCompletionSource<TResult> #this, TResult result, bool asyncAwaitContinuations)
{
if (!asyncAwaitContinuations)
{
#this.TrySetResult(result);
return;
}
var sc = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(SimpleSynchronizationContext.Instance);
try
{
#this.TrySetResult(result);
}
finally
{
SynchronizationContext.SetSynchronizationContext(sc);
}
}
}
}
I didn't want to use Task.Run(() => tcs.SetResult(result)) here, because it would be redundant to push continuations to ThreadPool when they're already scheduled to run asynchronously on a UI thread with a proper synchronization context. At the same time, if both StartAndControlWorkAsync and DoWorkAsync run on the same UI synchronization context, we'd also have a stack dive (if tcs.SetResult(result) is used without Task.Run or SynchronizationContext.Post wrapping).
Now, RunContinuationsAsynchronously is probably the best solution to this problem.

Continue with a method after completing producer-consumer

I have a producer-consumer application in WPF. After I click a button.
private async void Start_Click(object sender, RoutedEventArgs e)
{
try
{
// set up data
var producer = Producer();
var consumer = Consumer();
await Task.WhenAll(producer, consumer);
// need log the results in Summary method
Summary();
}
}
The summary method is a void one; I assume it is proper.
private void Summary(){}
async Task Producer(){ await something }
async Task Consumer(){ await something }
EDIT:
My question is in Summary() method I have to use the calculated values from the tasks, however the Consumer task is a long running process. The program run Summary quickly even not getting the updated values. It use the initial values.
My thought:
await Task.WhenAll(producer, consumer);
Summary();
EDIT2: 11:08 AM 11/05/2014
private void Summary()
{
myFail = 100 - mySuccess;
_dataContext.MyFail = myFail; // update window upon property changed
async Task Consumer()
{
try
{
Dictionary<string, string> dict = new Dictionary<string, string>();
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 5,
CancellationToken = cToken
};
var c = new ActionBlock<T>(
t=>
{
if (cToken.IsCancellationRequested)
return;
dict = Do(t, cToken);
if(dict["Success"] == "Success")
mySuccess++;
The current problem is mySuccess is always the initial value in Summary method.
You can use ContinueWith method to execute Summary after both producer and consumer have finished:
Task.WhenAll(producer, consumer)
.ContinueWith(continuation => Summary());
EDIT 1
It seems that you are abusing or using wrong the Producer/Consumer pattern.
The producer is supposed to produce the values and shovel them into one end of a communication pipe. On the other end of the pipe, the consumer consumes the values as they become available. In other words, the consumer waits for the producer to produce some value and to put the value in the pipe and for the value to arrive at the end of the pipe.
Usually this involves some sort of signaling mechanism where the producer signals (awakes) the consumer whenever a value has been created.
In your case, you don't have the signaling mechanism and I strongly suspect that your producer is generating only one value. If the later is the case you can just return a value from the "producer".
If however, your producer is creating more than one values, you can use the BlockingCollection<T> class to send values from producer to consumer.
In your Producer class, get a reference to the pipe and put data into it:
public class Producer
{
private BlockingCollection<Data> _pipe;
public void Start()
{
while(!done)
{
var value = ProduceValue();
_pipe.Add(value);
}
// Signal the consumer that we're finished
_pipe.CompleteAdding();
}
}
In the Consumer class wait for the values to arrive and process each one:
public class Consumer
{
private BlockingCollection<Data> _pipe;
public void Start()
{
foreach(var value in _pipe.GetConsumingEnumerable())
{
// GetConsumingEnumerable will block until a value arrives and
// will exit when producer calls CompleteAdding()
Process(value);
}
}
}
Having the above in place you can use ContinueWith or await on the WhenAll method to run the Summary.
EDIT 2
As promised in the comments I have analyzed the code you've posted on MSDN Forum. There are several problems in the code.
First of all and the simplest one to fix is that you're not incrementing the counter in a thread-safe manner. An increment (value++) is not an atomic operation so you should be careful when incrementing shared fields. An easy way to do this is:
Interlocked.Increment(ref evenNumber);
Now, the actual problems in your code:
As I mentioned earlier, the consumer does not know when the producer has finished producing the values. So, after the producer exits the for block it should signal that it has finished. The consumer waits for the finish signal of the producer; otherwise it will wait forever for the next value but there won't be one.
You are linking the BufferBlock with the consumer code which starts to execute but you're not waiting for the consumer block to finish - you're only waiting 0.5 of a second and exit the consumer method leaving the worker threads of the consumer block to do their work in vain.
As a consequence of the above, your Report method executes before the processing is finished outputting the value of the evenNumber counter at the moment when the method executes not when all processing is finished.
Below is the edited code with some comments:
class Program
{
public static BufferBlock<int> m_Queue = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1000 });
private static int evenNumber;
static void Main(string[] args)
{
var producer = Producer();
var consumer = Consumer();
Task.WhenAll(producer, consumer).Wait();
Report();
}
static void Report()
{
Console.WriteLine("There are {0} even numbers", evenNumber);
Console.Read();
}
static async Task Producer()
{
for (int i = 0; i < 500; i++)
{
// Send a value to the consumer and wait for the value to be processed
await m_Queue.SendAsync(i);
}
// Signal the consumer that there will be no more values
m_Queue.Complete();
}
static async Task Consumer()
{
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 4
};
var consumerBlock = new ActionBlock<int>(x =>
{
int j = DoWork(x);
if (j % 2 == 0)
// Increment the counter in a thread-safe way
Interlocked.Increment(ref evenNumber);
}, executionDataflowBlockOptions);
// Link the buffer to the consumer
using (m_Queue.LinkTo(consumerBlock, new DataflowLinkOptions { PropagateCompletion = true }))
{
// Wait for the consumer to finish.
// This method will exit after all the data from the buffer was processed.
await consumerBlock.Completion;
}
}
static int DoWork(int x)
{
Thread.Sleep(100);
return x;
}
}

Flags, loops and locks in async code

What I'm trying to do is create a 'Listener' which listens to several different Tcp ports at once, and pipes the messages to any Observers.
Pseudo-ish code:
private bool _Listen = false;
public void Start()
{
_Listen = true;
Task.Factory.StartNew(() => Listen(1);
Task.Factory.StartNew(() => Listen(2);
}
public void Stop()
{
_Listen = false;
}
private async void Listen(int port)
{
var tcp = new TcpClient();
while(_Listen)
{
await tcp.ConnectAsync(ip, port);
using (/*networkStream, BinaryReader, etc*/)
{
while(_Listen)
{
//Read from binary reader and OnNext to IObservable
}
}
}
}
(For brevity, I've omitted the try/catch inside the two whiles, both of which also check the flag)
My question is: should I be locking the flag, and if so, how does that tie-in with the async/await bits?
First of all, you should change your return type to Task, not void. async void methods are essentially fire-and-forget and can't be awaited or cancelled. They exist primarily to allow the creation of asynchronous event handlers or event-like code. They should never be used for normal asynchronous operations.
The TPL way to cooperatively cancel/abort/stop an asynchronous operation is to use a CancellationToken. You can check the token's IsCancellationRequested property to see if you need to cancel your operation and stop.
Even better, most asynchronous methods provided by the framework accept a CancellationToken so you can stop them immediatelly without waiting for them to return. You can use NetworkStream's ReadAsync(Byte[], Int32, Int32, CancellationToken) to read data and cancel immediatelly when someone calls your Stop method.
You could change your code to something like this:
CancellationTokenSource _source;
public void Start()
{
_source = new CancellationTokenSource();
Task.Factory.StartNew(() => Listen(1, _source.Token),_source.Token);
Task.Factory.StartNew(() => Listen(2, _source.Token), _source.Token);
}
public void Stop()
{
_source.Cancel();
}
private async Task Listen(int port,CancellationToken token)
{
var tcp = new TcpClient();
while(!token.IsCancellationRequested)
{
await tcp.ConnectAsync(ip, port);
using (var stream=tcp.GetStream())
{
...
try
{
await stream.ReadAsync(buffer, offset, count, token);
}
catch (OperationCanceledException ex)
{
//Handle Cancellation
}
...
}
}
}
You can read a lot more about cancellation in Cancellation in Managed Threads, including advice on how to poll, register a callback for cancellation, listen to multiple tokens etc.
The try/catch block exists because await throws an Exception if a Task is cancelled. You can avoid this by calling ContinueWith on the Task returned by ReadAsync and checking the IsCanceled flag:
private async Task Listen(int port,CancellationToken token)
{
var tcp = new TcpClient();
while(!token.IsCancellationRequested)
{
await tcp.ConnectAsync(ip, port);
using (var stream=tcp.GetStream())
{
///...
await stream.ReadAsync(buffer, offset, count, token)
.ContinueWith(t =>
{
if (t.IsCanceled)
{
//Do some cleanup?
}
else
{
//Process the buffer and send notifications
}
});
///...
}
}
}
await now awaits a simple Task that finishes when the continuation finishes
You would probably be better of sticking with RX all the way through instead of using Task. Here is some code I wrote for connecting to UDP sockets with RX.
public IObservable<UdpReceiveResult> StreamObserver
(int localPort, TimeSpan? timeout = null)
{
return Linq.Observable.Create<UdpReceiveResult>(observer =>
{
UdpClient client = new UdpClient(localPort);
var o = Linq.Observable.Defer(() => client.ReceiveAsync().ToObservable());
IDisposable subscription = null;
if ((timeout != null)) {
subscription = Linq.Observable.Timeout(o.Repeat(), timeout.Value).Subscribe(observer);
} else {
subscription = o.Repeat().Subscribe(observer);
}
return Disposable.Create(() =>
{
client.Close();
subscription.Dispose();
// Seems to take some time to close a socket so
// when we resubscribe there is an error. I
// really do NOT like this hack. TODO see if
// this can be improved
Thread.Sleep(TimeSpan.FromMilliseconds(200));
});
});
}
should I be locking the flag, and if so, how does that tie-in with the async/await bits?
You need to synchronize access to the flag somehow. If you don't, the compiler is allowed to make the following optimization:
bool compilerGeneratedLocal = _Listen;
while (compilerGeneratedLocal)
{
// body of the loop
}
Which would make your code wrong.
Some options how you can fix that:
Mark the bool flag volatile. This will ensure that the current value of the flag is always read.
Use CancellationToken (as suggested by Panagiotis Kanavos). This will make sure that the underlying flag is accessed in a thread-safe manner for you. It has also the advantage that many async methods support CancellationToken, so you can cancel them too.
Some form of Event (such as ManualResetEventSlim) would be a more obvious choice when you're potentially dealing with multiple threads.
private ManualResetEventSlim _Listen;
public void Start()
{
_Listen = new ManualResetEventSlim(true);
Task.Factory.StartNew(() => Listen(1);
Task.Factory.StartNew(() => Listen(2);
}
public void Stop()
{
_Listen.Reset();
}
private async void Listen(int port)
{
var tcp = new TcpClient();
while(_Listen.IsSet)
{

Categories