Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

370
Views
How to run a Task on a new thread and immediately return to the caller?

For the last few months I have been reading about async-await in C# and how to properly use it.

For the purpose of a laboratory exercise, I am building a small Tcp server that should serve clients that connect to it. The program is a console application.

I use a while loop to wait for connections like so:

while (!_isStopRequested)
{
       TcpClient client = await _tcpListener.AcceptTcpClientAsync();

       await Task.Factory.StartNew(() => ProcessClientAsync(client), TaskCreationOptions.LongRunning);
} 

So, until now the method ProcessClientAsync I made was marked as async void and I would just call it ProcessClientAsync(client) and the call would immediately return to the caller. However I read on the internet that it is a poor decision to use it unless it is for an event. So I changed the definition to async Task.

Ok, but without an await, I get a warning in Visual studio "Because this call is not awaited, the current method continues to run before the call is completed".

And once I used await ProcessClientAsync(client), the code doesn't work. I can connect only one client, and then the caller "waits" for ProcessClientAsync to return. However, that method has a infinite loop and will not return, but I need the while loop to continue processing the next client.

Googling I came up to this thread: How to safely call an async method in C# without await

I guess the questions are pretty much the same, except that when I use await ProcessClientAsync, I want it to return to the caller immediately, which it doesn't do, I know because running the second client, while the first is still running, the second client doesn't connect.

So I did this:

await Task.Factory.StartNew(() => ProcessClientAsync(client), TaskCreationOptions.LongRunning);

But since ProcessClientAsync has to return a Task, I am not sure if this is Ok to do?

That would be one question.

The other would be: how could I call a async Task method that will run forever, and have the call return to the caller immediately so the while loop can continue and the tcp listener can continue to accept the next client?

Thank you.

Sorry if it is a repetition, or unclear what I am asking.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

For the purpose of a laboratory exercise, I am building a small Tcp server that should serve clients that connect to it. The program is a console application.

Well, the very first thing I'd recommend is to try a simpler exercise. Seriously, an asynchronous TCP server is one of the most complex applications you can choose. The vast majority of developers using async are working on apps two orders of magnitude simpler.

Instead of that, try writing a UI app that will download a file from a URL. That's a more realistic starting point for learning async.

But since ProcessClientAsync has to return a Task, I am not sure if this is Ok to do?

I'd recommend using Task.Run instead of Task.Factory.StartNew. Task.Run is aware of async methods, whereas StartNew is not.

However, that's assuming that kicking off a thread is the correct operation in the first place. Most TCP/IP server applications are not CPU-bound, so I question the use of multiple threads here. It's entirely possible to have a fully-asynchronous TCP/IP server that only uses the thread pool for its async method continuations.

The other would be: how could I call a async Task method that will run forever, and have the call return to the caller immediately so the while loop can continue and the tcp listener can continue to accept the next client?

You just don't await the Task it returns:

Task.Run(() => ProcessClientAsync(client));

However, the compiler will complain here, because this code is almost certainly wrong. If you ignore the returned task, then you're ignoring any exceptions from that code.

A common pattern in TCP/IP server apps is to maintain a small collection of state for each connected client. That's a natural place to put both the socket object itself and the task that represents the handling of that socket connection:

var clientState = new ClientState(client);
clientState.Task = Task.Run(() => ProcessClientAsync(client));

These client states are then stored in a list/dictionary. How exactly you do this is of course up to you.

over 4 years ago · Santiago Trujillo Report

0

This will start the task and return to the caller, and avoid the compiler warning:

var t = Task.Factory.StartNew(() => {});
over 4 years ago · Santiago Trujillo Report

0

If I'm correct understand your problem then this code should help:

private async void AcceptClient(TcpClient client)
{
  await Task.Factory.StartNew(() => ProcessClientAsync(client), TaskCreationOptions.LongRunning);
}

private async void Run()
{
  while (!_isStopRequested)
  {
       TcpClient client = await _tcpListener.AcceptTcpClientAsync();
       AcceptClient(client);
  }
} 
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!