I am working on refactoring code that uses the Bootstrap protocol to update the firmware of several nodes in a machine. The current code looks something like this (pseudo-code):
public void StartUpdate()
{
Sokcet bootpSocket = new Socket():
StateObject bootpState = new StateObject(bootpSocket);
BOOTPReceive(bootpState);
SendMagicPacket();
while (!IsError && !IsUpdateComplete)
{
//wait for BOOTP/Update to finish before returning to caller
}
}
private void BOOTPReceive(object state)
{
bOOTPSocket.BeginReceive(PACKET_DATA, 0, PACKET_DATA.Length, 0, OnBOOTPReceive, state);
}
SendMagicPacket()
{
//create and send magic packet
// this will tell the node to respond with a BOOTPPacket
}
private void OnBOOTPReceive(IAsyncResult result)
{
StateObject state = (StateObject) result.AsyncState;
Socket handler = state.workSocket;
int bytesRcvd = handler.EndReceive(result);
packet = PACKET_DATA;
if(isValidBOOTP(packet))
{
SendBOOTPResponse();
}
else{
BOOTPReceive(); //keep listening for valid bootp response
}
}
private void SendBOOTPResponse()
{
UdpClient udpClient = new UdpClient();
udpClient.BeginSend(packetData, packetData.Length, BROADCAST_IP, (int)UdpPort.BOOTP_CLIENT_PORT, OnBOOTPSend, udpClient);
}
private void OnBOOTPSend(IAsyncResult result)
{
UdpClient udpClient = (UdpClient)result.AsyncState;
int bytesSent = udpClient.EndSend(result);
udpClient.Close();
}
What I want to do is convert this to async-await but still require that I don't return back to the caller right away. How would I go about doing this? Is this possible to do? And would this be the right thing to do since await-async propagates all the way to the top?
Pseudo-code of what I think this would look like:
public void StartUpdate()
{
bool result = await SendMagicPacket();
bool IsError = await BOOTPCommunication(); //Handles all of the BOOTP recieve/sends
//don't return to caller until BOOTPCommunication is completed. How do i do this?
}
You need to wait for the two tasks try the following:
public async Task StartUpdate()
{
var resultTask = SendMagicPacket();
var isErrorTask = BOOTPCommunication(); //Handles all of the BOOTP recieve/sends
await Task.WhenAll(new[]{resultTask, isErrorTask});
//don't return to caller until BOOTPCommunication is completed. How do i do this?
}
//wait for BOOTP/Update to finish before returning to caller
You don't need any async IO at all because you want to wait until all operations are done. I assume you have copied some sample code. Most sample code uses async socket APIs.
Switch everything over to synchronous socket APIs and you're done.
If you want to keep this async for some reason you can indeed switch to await and untangle this code. The pseudo-code you posted looks like a good goal. It forces the surrounding method to be async Task, though.
You can deal with that by making all callers recursively async as well. If you don't need to conserve threads you could block on that task and have a mostly synchronous call chain. At that point you lose all async benefits, though.
Radin was on the right track, but I think what you want is something like this:
You need to wait for the two tasks try the following:
public async Task StartUpdate()
{
var resultTask = SendMagicPacket();
var isErrorTask = BOOTPCommunication(); //Handles all of the BOOTP recieve/sends
Task.WhenAll(new[]{resultTask, isErrorTask}).Wait(); //Wait() will block so that the method doesn't return to the caller until both of the asynchronous tasks complete.
}
What that allows is SendMagicPacket and BOOTPCommunication to both fire simultaneously, but to wait for BOTH to complete. Using that pattern you can fire of N events simultaneously, while using Wait() to wait for all to finish so that the method itself returns synchronously.
Related
I'm not sure how to code this logic. I want to be able to listen for new messages outside of the code scope that receives the websocket messages. I have to be able to ultimately make an async function called WaitForMessage(string msg), so this can't really be achieved with events as far as I know. I use .NET Core. I thought the logic should look kind of like this:
var messages = new();
foo();
bar();
async task foo(){
while(messages.message != "foobar")
await messages.WaitForNewMessage();
}
async Task bar(){
Task.delay(5000);
messages.NewMessage("foobar");
}
Any alternative methods or ways of achieving my goal is much appreciated.
I tried using events, but I can't wait for an event to be raised, I can only subscribe a function to the event, so that doesn't seem like good practice / even possible.
If I am understanding you correctly, this code will be sufficient. I have not tested it as I don't know how your websocket message receiving code looks like.
public async Task WaitForMessage(string message)
{
while (true)
{
var read = await _reader.ReadToEndAsync(); //whatver your code is for async receiving a chunk of text
if (read == message)
{
break;
}
}
}
and then the calling code
async Task Foo()
{
while (true)
{
await messages.WaitForMessage("foobar");
}
}
I need to do some WebRequest to a certain endpoint every 2 seconds. I tried to do it with a Timer, the problem is that every call to the callback function is creating a different Thread and I'm havind some concurrence problems. So I decided to change my implementation and I was thinking about using a background worker with a sleep of two seconds inside or using async await but I don't see the advantages of using async await. Any advice? thank you.
This is the code that I will reimplement.
private void InitTimer()
{
TimerCallback callback = TimerCallbackFunction;
m_timer = new Timer(callback, null, 0, m_interval);
}
private void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
m_object = GetMyObject();
}
public MyObject GetMyObject()
{
MyObject myobject = new MyObject();
try
{
MemoryStream responseInMemory = CreateWebRequest(m_host, ENDPOINT);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
myObject = (MyObject) xmlSerializer.Deserialize(responseInMemory);
}
catch (InvalidOperationException ex)
{
m_logger.WriteError("Error getting MyObject: ", ex);
throw new XmlException();
}
return myObject;
}
private MemoryStream CreateWebRequest(string host, string endpoint)
{
WebRequest request = WebRequest.Create(host + endpoint);
using (var response = request.GetResponse())
{
return (MemoryStream) response.GetResponseStream();
}
}
EDIT: I have read this SO thread Async/await vs BackgroundWorker
async await is also concurrence. If you have concurrence problems and you want your application to have only one thread, you should avoid using async await.
However the best way to do WebRequest is to use async await, which does not block the main UI thread.
Use the bellow method, it will not block anything and it is recommended by Microsoft. https://msdn.microsoft.com/en-us/library/86wf6409(v=vs.110).aspx
private async Task<MemoryStream> CreateWebRequest(string host, string endpoint)
{
WebRequest request = WebRequest.Create(host + endpoint);
using (var response = await request.GetResponseAsync())
{
return (MemoryStream)response.GetResponseStream();
}
}
You don't mention what the concurrency problems are. It may be that the request takes so long that the next one starts before the previous one finishes. It could also be that the callback replaces the value in my_Object while readers are accessing it.
You can easily make a request every X seconds, asynchronously and without blocking, by using Task.Delay, eg:
ConcurrentQueue<MyObject> m_Responses=new ConcurrentQueue<MyObject>();
public async Task MyPollMethod(int interval)
{
while(...)
{
var result=await SomeAsyncCall();
m_Responses.Enqueue(result);
await Task.Delay(interval);
}
}
This will result in a polling call X seconds after the last one finishes.
It also avoids concurrency issues by storing the result in a concurrent queue instead of replacing the old value, perhaps while someone else was reading int.
Consumers of MyObject would call Dequeue to retrieve MyObject instances in the order they were received.
You could use the ConcurrentQueue to fix the current code too:
private void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
var result=GetMyObject();
m_Responses.Enqueue(result);
}
or
private async void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
var result=await GetMyObjectAsync();
m_Responses.Enqueue(result);
}
if you want to change your GetObject method to work asynchronously.
Since your request seems to take a long time, it's a good idea to make it asynchronous and avoid blocking the timer's ThreadPool thread while waiting for a network response.
How to transform the following callback-driven code to async/await pattern PROPERLY:
public class DeviceWrapper
{
// external device which provides real time stream of data
private InternalDevice device = new InternalDevice();
private List<int> accumulationBuffer = new List<int>();
public void StartReceiving()
{
// the following callback invocations might by synchronized by main
// UI message pump, particular window message pump
// or some other way
device.Synchronization = Synchronization.UI;
device.DataAvailable += DataAvailableHandler;
device.ReceivingStoppedOrErrorOccured += StopHandler;
device.Start();
}
private void DataAvailableHandler(object sender, DataEventArgs e)
{
// Filter data from e.Data and accumulate to accumulationBuffer field.
// If certail condition is met, signal pending task (if there is any)
//as complete return to the awaiting caller accumulationBuffer or perhaps temporary buffer created from accumulationBuffer
// in order to make it available to the caller.
// Handle also requested cancellation.
}
public Task<byte[]> GetData(CancellationToken token)
{
// create task returning data filtered and accumulated in DataAvailableHandler
}
}
// usage:
async void Test()
{
DeviceWrapper w = new DeviceWrapper();
w.StartReceiving();
while(true)
{
byte[] filteredData = await w.GetData(CancellationToken.Null);
Use(filteredData);
}
}
I have sought inspiration to solve this by reading .NET StreamReader class source, but it made me even more confused.
Thank you experts for any advice!
You're looking for TaskCompletionSource<byte[]>. This is an approximation of what it would look like:
public Task<byte[]> GetData(CancellationToken token)
{
cancellationToken.ThrowIfCancellationRequested;
var tcs = new TaskCompletionSource<byte[]>();
DataEventHandler dataHandler = null;
dataHandler = (o, e) =>
{
device.DataAvailable -= dataHandler;
tcs.SetResult(e.Data);
}
StopEventHandler stopHandler = null;
stopHandler = (os, se) =>
{
device.ReceivingStoppedOrErrorOccured -= stopHandler;
// Assuming stop handler has some sort of error property.
tcs.SetException(se.Exception);
}
device.DataAvailable += dataHandler;
device.ReceivingStoppedOrErrorOccured += stopHandler;
device.Start();
return tcs.Task;
}
If you use your async await properly your code would be much easier:
First of all:
If you want to call an async function you should be async yourself
every async function returns Task instead of void or Task<TResult> instead of TResult
There is one exception: the async event handler may return void
After you call an async function you can do other things until you need the answer. But you don't have to do other things.
Once you need the answer await for the Task, the result is the TResult.
Now implementing your example. There are several methods to solve this, but I think this typically is a producer - consumer pattern: we have an object that produces things in a tempo independant from another object that consumes them.
You can create this yourself, using semaphores to signal new data, but .NET already has something for this:
System.Threading.Tasks.DataFlow.BufferBlock.
You'll need to download a microsoft nuget package. See the remarks in MSDN description of BufferBlock.
A BufferBlock is something you send objects of type T to, while another task waits for objects of type T to arrive. Fully supports async / await.
Sender side:
The bufferblock implements ITargetBlock<T> where T is the type it sends.
You can send items of type T to any ITargetBlock
Consider making the sender a separate object with the ITargetBlock<T> as property.
Whenever it has data to distribute: Post it, or SendAsync if you want to use async / await. See later
Consumer side:
BufferBlock<T> implements als ISourceBlock<T>
The consumer gets the ISourceBlock where the sender sends his objects to, in this case the BufferBlock that the sender uses.
When started the consumer waits for data to arrive using Receive or ReceiveAsync.
Ok, lets put it all together:
public class DeviceWrapper
{
// external device which provides real time stream of data
private InternalDevice device = new InternalDevice();
// internal buffer replaced by the bufferBlock
BufferBlock<byte> bufferBlock = new BufferBlock<byte>()
public void StartReceiving() {...}
private async void DataAvailableHandler(object sender, DataEventArgs e)
{
// get the input and convert it to a byte
// post the byte to the buffer block asynchronously
byte byteToSend = ...
await this.bufferBlock.SendAsync(byteToSend);
}
public async Task<IEnumerable<byte>> GetData(CancellationToken token)
{
List<byte> receivedBytes = new List<byte>()
while (await this.BufferBlock.OutputAvailableAsync(token))
{ // a byte is available
byte b = await this.bufferBlock.ReceiveAsync(token);
receivedBytes.Add(b);
if (receivedBytes.Count > ...)
{
return receivedBytes;
}
// else: not enough bytes received yet, wait for more
}
}
}
async Task Test(CancellationToken token)
{
DeviceWrapper w = new DeviceWrapper();
w.StartReceiving();
while(NoStopRequested)
{
token.ThrowIfCancellationrequested();
var filteredData = await w.GetData(token);
Use(filteredData);
}
}
There is a lot more to tell with BufferBlocks, especially on how to stop them neatly if no data is available anymore MSDN has several examples about this.
See the chapter about DataFlow in parallel library
https://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx
I am trying to invoke a method from another .dll file .
It is sending a message through the VPN then Return the RecievedMessage from another computer.
As you now it takes time to sending and receiving message and VpnObject just send message and I should wait for listener to invoke the RecievedMessage.
This method is like this!
public string RecievedMessage()
{
string Recieved ;
// Some VPN Code and then return the result;
return Recieved;
}
public string SendAndRecieveMessage(string MessageToSend)
{
string RecievedAnswer = string.Empty;
// Now Sending Message through the VPN
VpnObject.SendMessage(MessageToSend);
//Then want to Recieve the answer and return the answer here .
return RecievedAnswer;
}
I'm just thinking how can wait for RecievedMessage to invoke then return the result .
You know it is simple to use a variable and assign it value and check for while but it reduced the performance dramatically .
Is there anyway to continue from SendAndRecieveMessage just when RecievedMessage invoked ? (I think it is something with async and await but don't know how!)
Edit :VpnObject is just a sender and receiver through the vpn . it contains a simple socket send and a listener that invoke a method(RecievedMessage) when new message received .
Whether or not you have an alternative to polling depends on whether the library you are using provides any events or callbacks that will tell you when the request has completed.
Either way, the standard approach to exposing the deferred result of an asynchronous operation is to use a Task. Your method signature would look like this:
public Task<string> SendAndRecieveMessage(string MessageToSend)
Now, how you actually implement the method depends on what API VpnObject exposes. TaskCompletionSource is very useful for this kind of thing.
If VpnObject has an event that fires when the request completes:
public Task<string> SendAndReceiveMessage(string messageToSend)
{
var tcs = new TaskCompletionSource<string>();
...
VpnObject.OnMessageReceived += (s, e) => tcs.SetResult(e.Message);
...
return tcs.Task;
}
If VpnObject can accept a callback that it will invoke when the request completes:
public Task<string> SendAndReceiveMessage(string messageToSend)
{
var tcs = new TaskCompletionSource<string>();
...
VpnObject.OnMessageReceived(message => tcs.SetResult(message));
...
return tcs.Task;
}
If VpnObject doesn't support any of this, you can fall back to polling:
public async Task<string> SendAndReceiveMessage(string messageToSend)
{
var tcs = new TaskCompletionSource<string>();
...
while(!VpnObject.IsMessageReceived)
await Task.Delay(500); // Adjust to a reasonable polling interval
...
return VpnObject.Message;
}
You know it is simple to use a variable and assign it value and check for while but it reduced the performance dramatically .
A spin while loop is definitely not the way to implement this. Even with a sleep, it's clunky, and C# has multiple ways to solve this problem.
It's not entirely clear how your VPN Send and Receive method works, but the idea for solving this is to either use a callback approach, or as you noted, use C# async framework.
Without more details on the VPN Object, I'll just have to have some stub methods. The idea is to create a Task that returns the string, mark it as an async task, then await for it to complete. In your case, the task is receiving the VPN response string.
Something like this.
public Task<string> ReceivedMessage()
{
//get the response from the VPN Object.
string Received = VpnObject.GetResponse();
var ts = new TaskCompletionSource<string>();
ts.SetResult(Received);
// Some VPN Code and then return the result;
return ts.Task;
}
public async Task<string> SendAndReceiveMessageAsync(string MessageToSend)
{
string result = string.Empty;
// Now Sending Message through the VPN
VpnObject.SendMessage(MessageToSend);
result = await ReceivedMessage();
return result;
}
I'm about 15 minutes into my first play with the async CTP... (nice).
Here's a really simple server I've knocked together:
internal class Server
{
private HttpListener listener;
public Server()
{
listener = new HttpListener();
listener.Prefixes.Add("http://*:80/asynctest/");
listener.Start();
Go();
}
async void Go()
{
HttpListenerContext context = await listener.GetContextAsync();
Go();
using (var httpListenerResponse = context.Response)
using (var outputStream = httpListenerResponse.OutputStream)
using (var sw = new StreamWriter(outputStream))
{
await sw.WriteAsync("hello world");
}
}
}
As can be seen, the async method Go calls itself. In classic non-async world, this would cause a stack overflow. I assume that this isn't the case with an async method, but I'd like to be sure, one way or the other. Anyone?
Let's break it down into something simpler:
async static void Go()
{
await Something();
Go();
await SomethingElse();
}
How does the compiler deal with this?
Basically this becomes something like this sketch:
class HelperClass
{
private State state = STARTSTATE;
public void DoIt()
{
if (state == STARTSTATE) goto START;
if (state == AFTERSOMETHINGSTATE) goto AFTERSOMETHING;
if (state == AFTERSOMETHINGELSESTATE) goto AFTERSOMETHINGELSE;
START:
{
state = AFTERSOMETHINGSTATE;
var awaiter = Something().MakeAnAwaiter();
awaiter.WhenDoneDo(DoIt);
return;
}
AFTERSOMETHING:
{
Go();
state = AFTERSOMETHINGELSESTATE;
var awaiter = SomethingElse().MakeAnAwaiter();
awaiter.WhenDoneDo(DoIt);
return;
}
AFTERSOMETHINGELSE:
return;
}
static void Go()
{
var helper = new HelperClass();
helper.DoIt();
}
Now all you have to remember is that when each asynchronous operation completes, "DoIt" is scheduled to be called again by the message loop (on the appropriate instance of the helper of course).
So what happens? Work it out. You call Go for the first time. That makes helper number one and calls DoIt. That calls Something(), gets a task back, makes an awaiter for that task, tells the awaiter "when you're done, call helper1.DoIt" and returns.
A tenth of a second later the task completes and the message loop calls helper1's DoIt. helper1's state is AFTERSOMETHINGSTATE, so we take the goto and call Go. That makes helper2 and calls DoIt on that. That calls Something(), gets a task back, makes an awaiter for that task, tells the awaiter "when you're done, call DoIt on helper2" and returns control back to helper1's DoIt. That calls SomethingElse, makes an awaiter for that task, and tells it "when you're done doing something else, call helper1's DoIt". It then returns.
Now we have two tasks outstanding and no code on the stack. One of the tasks will complete first. Suppose the SomethingElse task completes first. The message loop calls helper1.DoIt(), which immediately returns. Helper1 is now garbage.
Later the message loop calls helper2.DoIt(), and branches to AFTERSOMETHING. Now Go() is called, which creates helper3...
So no, there's no unbounded recursion here. Every time Go executes it runs as far as asynchronously starting Something() and then it returns to its caller. The call to the stuff after "something" happens later. "Go" is only ever on the stack once at a time.