Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TaskCompletionSource in async function

Tags:

c#

.net

I have such a function:

public async Task<bool> DoSomething()
{
   var tcs = new TaskCompletionSource<bool>();

   // Here is the problem. I need to keep this line because I wait on something asynchronously, but the function must return bool and I can't just return tcs.Task
   while(something)
      await Task.Delay(100);

   someobject.somevent += () => {
      // do some sht
      tcs.SetResult(true);
   }

   // it doesn't work
   return tcs.Task;
}

It's just a fake code but I have real situation where I need this. I want to keep DoSomething asynchronous but I also want to keep Task.Delay/Sleep in it. How do I do this in not-async function returning just Task?

UPDATE:

THIS WORKS:

class Program
    {
        static TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();


        static Task<bool> Test()
        {
           // tcs = new TaskCompletionSource<bool>();
            Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Waiting...");
                Thread.Sleep(5000);
                Console.WriteLine("Setting result");
                if(tcs.TrySetResult(true))
                    Console.WriteLine("Result has been set");


            });

            return tcs.Task;
        }

        static async Task Test2()
        {
            Console.WriteLine("Starting awaiting");
            var result = await Test();
            Console.WriteLine(result.ToString());
        }

        static void Main(string[] args)
        {


            Test2();

            Console.ReadKey(false);

        }
    }

and this doesn't

static async Task<bool> Test()
{
   // tcs = new TaskCompletionSource<bool>();
    Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Waiting...");
        Thread.Sleep(5000);
        Console.WriteLine("Setting result");
        if(tcs.TrySetResult(true))
            Console.WriteLine("Result has been set");


    });


    return await tcs.Task;
}

what's worse, I have tested it in my windows forms app and awaiting tcs.Task caused weird crash coming from System.Threading....dll

like image 948
Konrad Avatar asked Feb 02 '16 16:02

Konrad


People also ask

What is the use of TaskCompletionSource?

Run turns something synchronous into a Task (by running it on a separate thread), TaskCompletionSource turns something that is already asynchronous into a Task . "If it is already asynchronous, why does it need to be turned into a Task ?"

Is TaskCompletionSource thread safe?

Is it safe to pass non-thread-safe objects created on one thread to another using TaskCompletionSource. SetResult()? Yes, as long as the object can be used on a different thread than the one it was created on (of course).

What is async await in C#?

An async keyword is a method that performs asynchronous tasks such as fetching data from a database, reading a file, etc, they can be marked as “async”. Whereas await keyword making “await” to a statement means suspending the execution of the async method it is residing in until the asynchronous task completes.

How do I run a task in C#?

To start a task in C#, follow any of the below given ways. Use a delegate to start a task. Task t = new Task(delegate { PrintMessage(); }); t. Start();


2 Answers

If I understand correctly (it's tricky because your question isn't that easy to follow) you can restate things as follows:

public async Task<bool> DoSomething()
{
   var tcs = new TaskCompletionSource<bool>();
   someobject.somevent += () => {
      // do some sht
      tcs.SetResult(true);
   }

   return await tcs.Task;
}
like image 114
spender Avatar answered Oct 12 '22 02:10

spender


The whole thing will come out a lot more elegantly if you separate out the logic of turning the event firing into a Task into its own method.

public static Task<bool> WhenSomeEvent(this SomeObject someobject)
{
    var tcs = new TaskCompletionSource<bool>();
    Action handler = null;
    handler = () =>
    {
        tcs.SetResult(true);
        someobject.SomeEvent -= handler;
    };
    someobject.SomeEvent += handler;
    return tcs.Task;
}

This allows you to write the business logic separately, without mixing in all of the logic of translating the event into a Task:

public async Task<bool> DoSomething()
{
    while(something)
        await Task.Delay(100);

    return await someobject.WhenSomeEvent();
}
like image 28
Servy Avatar answered Oct 12 '22 02:10

Servy