I am in this situation:
many clients can send commands to a controller, and the controller must process each command in order, and send back a response to each client. The clients "awaits" for the response asynchronously.
So, by now, when i receive a command from a client, i enqueue the command in a ConcurrentQueue and run a Task where the client waits for a response asynchronously. The controller has a Thread that is always searching for new commands at the ConcurrentQueue, takes the first, process it and should response to the sender (the client), but here is where i get stuck because i don´t know how to make the controller responds EXACTLY to the client that sent the command (the controller has a queue with many commands but doesn´t know who sent them).
My thinking:
It would be great to send a message from a Thread directly to a Task with the response object. Is it something possible?
My code:
private ConcurrentQueue<byte[]> sendBuffer;
public async Task<IViewAppMessage> sendCommandAsync(byte[] command)
{
sendBuffer.Enqueue(command);
return await Task.Run<IViewAppMessage>(() =>
{
//Pool for a response
}
}
/* Method executed within a Timer worker thread */
private void senderPool(object stateInfo)
{
try
{
//Stop timer
senderTimer.Change(Timeout.Infinite, Timeout.Infinite);
//Take command from FIFO
byte[] commandToSend;
if(sendBuffer.TryDequeue(out commandToSend))
{
//Send command to camera
cameraSender.Send(commandToSend, commandToSend.Length);
byte[] response = cameraListener.Receive(ref endPoint);
IViewAppMessage returnMessage = processResponse(response);
//Notify the response. HOW?????????????
}
}
catch
{
//Notify Error
}
//In any case, timer restarts
finally
{
try
{
//Arrancamos timer
senderTimer.Change(100, Timeout.Infinite);
}
catch
{
//Fatal error
}
}
}
Thanks!
EDIT:
I know i could use a BlockingCollection with all the reponses, so when the sender receives a response, it allocate it at the collection, and then the clients polls for a response, but with that approach i should give each client an ID (or something similar) to check for a response with its ID. That could be a solution, but i wonder if is it possible to directly send a message to the task with the response, since i think something similar would be a better approach since it wouldn´t be neccesary to make the clients poll nor assing them not concurrent IDs.
Do not just enqueue the item to be sent. Include data that allows the consumer to notify the producer. For example, you could include a TaskCompletionSource that is set to completed by the consumer at the appropriate point. The producer can await TaskCompletionSource.Task.
You can use a BlockingCollection instead of the queue - classic producer consumer pattern, check the example in MSDN documentation. This would eliminate the use of timer since queue.Take() would block until an item is available in the queue.
Related
I'm developing a game server. Through TCPListener I accept clients.
var Listener = new TcpListener(IPAddress.Any, CommonConfig.Settings.GamePort);
Listener.Start();
ListenerStarted = true;
while (ListenerStarted)
{
TcpClient tcpClient = await Listener.AcceptTcpClientAsync();
ProcessClientTearOff(tcpClient);
}
Then through ReadAsync is getting the data from the client.
byte[] Buffer = new byte[8192];
int i = await Stream.ReadAsync(Buffer, 0, 8192);
After that, the data is processed using the method
RequestHandling(byte[] data)
and performing various actions. Clients actively interact between each other and therefore there are problems with thread safety. I was looking for information on how to properly organize the server structure and found a possible case that the data is being received asynchronously (as I have now), but the processing and execution of actions occurs in one thread.
One thread to accept clients and get data, one thread to process and execute, one thread to send data to clients.
But I can not understand how this can be realized. Through Task, you can specify the order in which the methods are executed, but only before running tasks. Is it possible to run all the processing of packets in a separate thread so that all actions are executed synchronously in the order of the queue? Or is there any alternative to this?
The question is fairly vague which is understandable given that you are seeking a general concept to organize this.
You don't need a separate thread to process a queue. Usually, a lock is an easier solution. A lock has an internal queue as am implementation detail. The queue contains the threads that are waiting to enter.
A good pattern for your case seems to be the following. Make each connection thread/task execute this loop:
while (true) {
var message = await ReceiveMessageFromNetwork();
lock (globalLock) {
ApplyMessage(message); //no IO here
}
}
The queue is implicit in the lock. I marked some code as "no IO" because you have to quickly leave the lock so that other threads/tasks can enter.
I have been struggling a bit with some async await stuff. I am using RabbitMQ for sending/receiving messages between some programs.
As a bit of background, the RabbitMQ client uses 3 or so threads that I can see: A connection thread and two heartbeat threads. Whenever a message is received via TCP, the connection thread handles it and calls a callback which I have supplied via an interface. The documentation says that it is best to avoid doing lots of work during this call since its done on the same thread as the connection and things need to continue on. They supply a QueueingBasicConsumer which has a blocking 'Dequeue' method which is used to wait for a message to be received.
I wanted my consumers to be able to actually release their thread context during this waiting time so somebody else could do some work, so I decided to use async/await tasks. I wrote an AwaitableBasicConsumer class which uses TaskCompletionSources in the following fashion:
I have an awaitable Dequeue method:
public Task<RabbitMQ.Client.Events.BasicDeliverEventArgs> DequeueAsync(CancellationToken cancellationToken)
{
//we are enqueueing a TCS. This is a "read"
rwLock.EnterReadLock();
try
{
TaskCompletionSource<RabbitMQ.Client.Events.BasicDeliverEventArgs> tcs = new TaskCompletionSource<RabbitMQ.Client.Events.BasicDeliverEventArgs>();
//if we are cancelled before we finish, this will cause the tcs to become cancelled
cancellationToken.Register(() =>
{
tcs.TrySetCanceled();
});
//if there is something in the undelivered queue, the task will be immediately completed
//otherwise, we queue the task into deliveryTCS
if (!TryDeliverUndelivered(tcs))
deliveryTCS.Enqueue(tcs);
}
return tcs.Task;
}
finally
{
rwLock.ExitReadLock();
}
}
The callback which the rabbitmq client calls fulfills the tasks: This is called from the context of the AMQP Connection thread
public void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, RabbitMQ.Client.IBasicProperties properties, byte[] body)
{
//we want nothing added while we remove. We also block until everybody is done.
rwLock.EnterWriteLock();
try
{
RabbitMQ.Client.Events.BasicDeliverEventArgs e = new RabbitMQ.Client.Events.BasicDeliverEventArgs(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body);
bool sent = false;
TaskCompletionSource<RabbitMQ.Client.Events.BasicDeliverEventArgs> tcs;
while (deliveryTCS.TryDequeue(out tcs))
{
//once we manage to actually set somebody's result, we are done with handling this
if (tcs.TrySetResult(e))
{
sent = true;
break;
}
}
//if nothing was sent, we queue up what we got so that somebody can get it later.
/**
* Without the rwlock, this logic would cause concurrency problems in the case where after the while block completes without sending, somebody enqueues themselves. They would get the
* next message and the person who enqueues after them would get the message received now. Locking prevents that from happening since nobody can add to the queue while we are
* doing our thing here.
*/
if (!sent)
{
undelivered.Enqueue(e);
}
}
finally
{
rwLock.ExitWriteLock();
}
}
rwLock is a ReaderWriterLockSlim. The two queues (deliveryTCS and undelivered) are ConcurrentQueues.
The problem:
Every once in a while, the method that awaits the dequeue method throws an exception. This would not normally be an issue since that method is also async and so it enters the "Exception" completion state that tasks enter. The problem comes in the situation where the task that calls DequeueAsync is resumed after the await on the AMQP Connection thread that the RabbitMQ client creates. Normally I have seen tasks resume onto the main thread or one of the worker threads floating around. However, when it resumes onto the AMQP thread and an exception is thrown, everything stalls. The task does not enter its "Exception state" and the AMQP Connection thread is left saying that it is executing the method that had the exception occur.
My main confusion here is why this doesn't work:
var task = c.RunAsync(); //<-- This method awaits the DequeueAsync and throws an exception afterwards
ConsumerTaskState state = new ConsumerTaskState()
{
Connection = connection,
CancellationToken = cancellationToken
};
//if there is a problem, we execute our faulted method
//PROBLEM: If task fails when its resumed onto the AMQP thread, this method is never called
task.ContinueWith(this.OnFaulted, state, TaskContinuationOptions.OnlyOnFaulted);
Here is the RunAsync method, set up for the test:
public async Task RunAsync()
{
using (var channel = this.Connection.CreateModel())
{
...
AwaitableBasicConsumer consumer = new AwaitableBasicConsumer(channel);
var result = consumer.DequeueAsync(this.CancellationToken);
//wait until we find something to eat
await result;
throw new NotImplementeException(); //<-- the test exception. Normally this causes OnFaulted to be called, but sometimes, it stalls
...
} //<-- This is where the debugger says the thread is sitting at when I find it in the stalled state
}
Reading what I have written, I see that I may not have explained my problem very well. If clarification is needed, just ask.
My solutions that I have come up with are as follows:
Remove all Async/Await code and just use straight up threads and block. Performance will be decreased, but at least it won't stall sometimes
Somehow exempt the AMQP threads from being used for resuming tasks. I assume that they were sleeping or something and then the default TaskScheduler decided to use them. If I could find a way to tell the task scheduler that those threads are off limits, that would be great.
Does anyone have an explanation for why this is happening or any suggestions to solving this? Right now I am removing the async code just so that the program is reliable, but I really want to understand what is going on here.
I first recommend that you read my async intro, which explains in precise terms how await will capture a context and use that to resume execution. In short, it will capture the current SynchronizationContext (or the current TaskScheduler if SynchronizationContext.Current is null).
The other important detail is that async continuations are scheduled with TaskContinuationOptions.ExecuteSynchronously (as #svick pointed out in a comment). I have a blog post about this but AFAIK it is not officially documented anywhere. This detail does make writing an async producer/consumer queue difficult.
The reason await isn't "switching back to the original context" is (probably) because the RabbitMQ threads don't have a SynchronizationContext or TaskScheduler - thus, the continuation is executed directly when you call TrySetResult because those threads look just like regular thread pool threads.
BTW, reading through your code, I suspect your use of a reader/writer lock and concurrent queues are incorrect. I can't be sure without seeing the whole code, but that's my impression.
I strongly recommend you use an existing async queue and build a consumer around that (in other words, let someone else do the hard part :). The BufferBlock<T> type in TPL Dataflow can act as an async queue; that would be my first recommendation if you have Dataflow available on your platform. Otherwise, I have an AsyncProducerConsumerQueue type in my AsyncEx library, or you could write your own (as I describe on my blog).
Here's an example using BufferBlock<T>:
private readonly BufferBlock<RabbitMQ.Client.Events.BasicDeliverEventArgs> _queue = new BufferBlock<RabbitMQ.Client.Events.BasicDeliverEventArgs>();
public void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, RabbitMQ.Client.IBasicProperties properties, byte[] body)
{
RabbitMQ.Client.Events.BasicDeliverEventArgs e = new RabbitMQ.Client.Events.BasicDeliverEventArgs(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body);
_queue.Post(e);
}
public Task<RabbitMQ.Client.Events.BasicDeliverEventArgs> DequeueAsync(CancellationToken cancellationToken)
{
return _queue.ReceiveAsync(cancellationToken);
}
In this example, I'm keeping your DequeueAsync API. However, once you start using TPL Dataflow, consider using it elsewhere as well. When you need a queue like this, it's common to find other parts of your code that would also benefit from a dataflow approach. E.g., instead of having a bunch of methods calling DequeueAsync, you could link your BufferBlock to an ActionBlock.
I have stumbled upon this problem many times, mostly solved it with hacks, but would like to see a "proprer" way to do it.
I'm writing a communication protocol, very similar to RPC in a way that my endpoints ask "queries", to which they receive "replies".
Now... I would like to implement a function, called SendCommand, that would send out a query, and wait for the reply to that question, and return it.
So I could do something like
int outside_temp = SendCommand(What is the temperature outside).ToInt();
The problem with this is that the messages are send and received asynchronously, and I am notified by events that a new message has arrived, and what it was. I would need to block the thread until the reply to the mentioned query has arrived, extract its data content, and return it to the caller.
My problem is with blocking the thread. Blocking the thread is not a problem, we are talking about a multi-threaded app, so the UI would not freeze, etc., but the question is what is the correct way to achieve this?
I'm thinking something along the line of initializing a semaphore inside the SendCommand function, waiting for it, and release the semaphore in the message received event handler (after checking it was the correct message)?
Regards,
axos88
So your question is about blocking the current thread and wait for the answer?
I would use a ManualResetEvent to synchronise the caller and the callback.
Supposed you can send your rpc call via a Send method of an object which accepts a callback method, you can code your SendCommand method like this:
int SendCommand(int param)
{
ManualResetEvent mre = new ManualResetEvent(false);
// this is the result which will be set in the callback
int result = 0;
// Send an async command with some data and specify a callback method
rpc.SendAsync(data, (returnData) =>
{
// extract / process your return value and
// assign it to an outer scope variable
result = returnData.IntValue;
// signal the blocked thread to continue
mre.Set();
});
// wait for the callback
mre.WaitOne();
return result;
}
What you could do is, spin a new thread that calls SendCommand(..) and just wait far the thread with sleeping until your SendCommand sends a signal.
For example:
volatile bool commandCompleted=false;
Thread sendCommandThread=new Thread(()=>{
SendCommand(...,()=>{
commandCompleted=true;
})
while(!commandCompleted)
{
Thread.Sleep(100);
}
});
I've recently been playing around with the new Async CTP, and I've come across a situation where I'm not sure how to proceed.
In my current code base, I'm using a concept of "jobs" and a "job manager". Jobs exist solely for the purpose of handling an initial message, sending a response, and then waiting the response.
I already have existing code based around synchronous sockets, where a network thread is waiting on data to arrive, and then passing it along to an event handler, and eventually to the job manager.
The job manager looks for what job would handle the message, and passes it along.
So the scenario is this:
Job manager gets a new message and launches a job.
The job starts, processes the message, and sends a reply message.
At this point the job would wait for a response to the reply.
Here's a pseudocode example:
class MyJob : Job
{
public override void RunJob( IPacketMsg packet )
{
// handle packet
var myReply = new Packet();
SendReply( myReply );
await GetResponse();
}
}
But I'm not entirely sure how to proceed at step 3. The job manager will get the response and then hand it along to the running job. But I'm not sure how to make the job wait for the response.
I've considered creating an awaited Task that simply blocks on a WaitHandle, but is this the best solution?
Are there any other things I could do in this case?
Edit
On the subject of the Async CTP, what happens in a situation where the UI is not being used. I've read over Eric Lippert's Async blog, but I don't believe it ever touched on the subject of how everything works in the background without a UI thread (does it spin off a background worker or...?)
Job manager gets a new message and launches a job.
The job starts, processes the message, and sends a reply message.
At this point the job would wait for a response to the reply.
First off, I should mention that the Async CTP handles asynchronous operations very well, but asynchronous events not so much. You may want to consider an Rx-based approach. But let's proceed for the moment with the Async CTP.
You have two basic options to create Tasks:
With a delegate. e.g., Task.Factory.StartNew will run a delegate on the thread pool. Custom task factories and schedulers give you more options for task delegates (e.g., specifying the delegate must be run on an STA thread).
Without a delegate. e.g., TaskFactory.FromAsync wraps an existing Begin/End method pair, TaskEx.FromResult returns a "future constant", and TaskCompletionSource can be used to control a Task explicitly (both FromAsync and FromResult use TCS internally).
If the job processing is CPU-bound, it makes sense to pass it off to Task.Factory.StartNew. I'm going to assume the job processing is CPU-bound.
Job manager pseudo-code:
// Responds to a new message by starting a new job on the thread pool.
private void RespondToNewMessage(IPacketMsg message)
{
IJob job = ..;
Task.Factory.StartNew(job.RunJob(message));
}
// Holds tasks waiting for a response.
private ConcurrentDictionary<int, TaskCompletionSource<IResponse>> responseTasks = ..;
// Asynchronously gets a response for the specified reply.
public Task<IResponse> GetResponseForReplyAsync(int replyId)
{
var tcs = new TaskCompletionSource<IResponse>();
responseTasks.Add(replyId, tcs);
return tcs.Task;
}
// Responds to a new response by completing and removing its task.
private void RespondToResponse(IResponse response)
{
var tcs = responseTasks[response.ReplyId];
responseTasks.Remove(response.ReplyId);
tcs.TrySetComplete(response);
}
The idea is that the job manager also manages a list of oustanding responses. In order for this to happen, I introduced a simple int reply identifier that the job manager can use to determine which response goes with which reply.
Now jobs can work like this:
public override void RunJob(IPacketMsg packet)
{
// handle packet
var myReply = new Packet();
var response = jobManager.GetResponseForReplyAsync(myReply.ReplyId);
SendReply(myReply);
await response;
}
There's a few tricky things since we're placing the jobs on the thread pool thread:
GetResponseForReplyAsync must be invoked (registering the task) before the reply is sent, and is then awaited later. This is to avoid the situation where a reply may be sent and a response received before we have a chance to register for it.
RespondToResponse will remove the task registration before completing it, just in case completing the task causes another reply to be sent with the same id.
If the jobs are short enough that they don't need to be placed on the thread pool thread, then the solution can be simplified.
On the subject of the Async CTP, what happens in a situation where the UI is not being used. I've read over Eric Lippert's Async blog, but I don't believe it ever touched on the subject of how everything works in the background without a UI thread (does it spin off a background worker or...?)
await will return to its synchronization context. In a UI process, this is a UI message loop. In ASP.NET, this is the ASP.NET thread pool. In other situations (Console applications and Win32 services), there is no context, so continuations are queued to the ThreadPool. This is not usually desired behavior, so I wrote an AsyncContext class that can be used in those situations.
BackgroundWorker is not used. In a server-side scenario such as yours, it's not uncommon to not have a background thread at all.
You would simply wire up the rest of your event handler with the await pattern like so:
public async void RunJob(IPacketMsg msg)
{
// Do Stuff
var response = await GetResponse();
// response is "string", not "Task<string>"
// Do More Stuff
}
public Task<string> GetResponse()
{
return Task.Factory.StartNew(() =>
{
_networkThingy.WaitForDataAvailable();
return _networkThingy.ResponseString;
});
}
When your get response task finishes, the rest of the method picks up execution on your current synchronization context. Until then, however, your method execution is yielded (so any code after the wait is not run until the task started in GetResponse finishes)
I have a synchronous web service call that returns a message. I need to quickly return a message that basically says that order was received. I then need to spend a couple of minutes processing the order, but cannot block the service call for that long. So how can I return from the web service, and then do some more stuff? I'm guessing I need to fork some other thread or something before I return, but I'm not sure of the best approach.
string ProcessOrder(Order order)
{
if(order.IsValid)
{
return "Great!";
//Then I need to process the order
}
}
You can open a new thread and have it do what you need, while you're main thread returns great.
string ProcessOrder(Order order)
{
if(order.IsValid)
{
//Starts a new thread
ThreadPool.QueueUserWorkItem(th =>
{
//Process Order here
});
return "Great!";
}
}
You could start your big amount of work in a seperate thread
public string ProcessOrder(Order order)
{
if(order.IsValid)
{
System.Threading.ParameterizedThreadStart pts = new System.Threading.ParameterizedThreadStart(DoHardWork);
System.Threading.Thread t = new System.Threading.Thread(pts);
t.Start(order);
return "Great!!!";
}
}
public void DoHardWork(object order)
{
//Stuff Goes Here
}
Is the work you're doing "important?" I assume it is. You could use a thread, but you'll have to be ok with the possibility that your work might get interrupted if the machine restarts or possibly if the asp.net worker process recycles. This would likely lead to the work not getting done even though you already told the client you had accepted it. This might be or not depending on your use case.
I would consider taking the work item you receive from the synchronous service request and putting it in a persistent queue. An easy way to do this is to use a transational MSMQ queue. Your synchronous service puts the work request in the queue and you have a few worker threads pulling work requests out of the queue. Wrap your queue read and the work in a transaction and don't commit the transaction until the work is completed. If you machine or process shuts down in the middle of a request, it will be restarted automatically the next time it starts up.
You could also look at utilizing the PIAB (Policy Injection Application Block) to accomplish work after a method call.