Eitan
Eitan

Reputation: 1504

c# - How to execute code on the main thread until a Task finishes

I'd like to understand the TPL a little bit better. How would I for example write something to the screen until a task finishes. I can't call 'await' because I want the main thread to be notified instead of proactively calling 'await' and I don't want to stop execution until the task is finished.

Some example code:

var task = Task.Run(()=>
{
   Task.Delay(10000);
});


while(true)
{
    Console.WriteLine("Running...");
    //I want to exit the loop the second 'task' finishes
    //and print 'finished'
}

Upvotes: 0

Views: 10212

Answers (4)

Karan
Karan

Reputation: 12629

You can achieve your goal using creating separate function to use in Task.Run and passing parameter by reference. Function should be something like below.

private void PerformTask(ref bool isComplete)
{
    System.Threading.Thread.Sleep(5000);
    isComplete = true;
}

Call above function from Task.Run. Your current function should be like below.

bool isComplete = false;
System.Threading.Tasks.Task.Run(() => PerformTask(ref isComplete));

while (!isComplete)
{
    Console.WriteLine("Running...");
    System.Threading.Thread.Sleep(1000);
}

Upvotes: 1

Barr J
Barr J

Reputation: 10927

There are a a couple of ways you cam achieve this:

First you can use Lambda expression in Order to invoke your action, but look at the code:

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      Console.WriteLine("Application thread ID: {0}",
                        Thread.CurrentThread.ManagedThreadId);
      var t = Task.Run(() => {  Console.WriteLine("Task thread ID: {0}",
                                   Thread.CurrentThread.ManagedThreadId);
                             } );
      t.Wait();
   }
}
// The example displays the following output:
//       Application thread ID: 1
//  

notice the t.Wait():

The call to the Wait method ensures that the task completes and displays its output before the application ends. Otherwise, it is possible that the Main method will complete before the task finishes.

So we understand that it's imperative to call the Wait() method in order make sure that the task completes and displays its output.

You can use the second way also:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      var list = new ConcurrentBag<string>();
      string[] dirNames = { ".", ".." };
      List<Task> tasks = new List<Task>();
      foreach (var dirName in dirNames) {
         Task t = Task.Run( () => { foreach(var path in Directory.GetFiles(dirName)) 
                                       list.Add(path); }  );
         tasks.Add(t);
      }
      Task.WaitAll(tasks.ToArray());
      foreach (Task t in tasks)
         Console.WriteLine("Task {0} Status: {1}", t.Id, t.Status);

      Console.WriteLine("Number of files read: {0}", list.Count);
   }
}

For more reference see Task.Run Method.


One highlight regarding your quesion:

taken from Asynchronous programming with async and await (C#):

An async method typically contains one or more occurrences of an await operator, but the absence of await expressions doesn’t cause a compiler error. If an async method doesn’t use an await operator to mark a suspension point, the method executes as a synchronous method does, despite the async modifier. The compiler issues a warning for such methods.

That implies that either way you will have to wait for your tasks to finish and the main thread will have to wait this way or another.

Upvotes: 2

KozhevnikovDmitry
KozhevnikovDmitry

Reputation: 1720

Try to do something like this:

var task = Task.Run(() =>
{
    Task.Delay(10000).Wait();
});


bool terminate = false;
while (!task.GetAwaiter().IsCompleted && !terminate)
{
    // do something 

    if (task.GetAwaiter().IsCompleted) break;
    // do something heavy

    if (task.GetAwaiter().IsCompleted) break;
    // do another heavy operation

    for (int i = 0; i < 10000; i++)
    {
        // it took too long!
        if (i == 1000)
        {
            terminate = true;
            break;
        }
    }

}

Upvotes: 0

Ankur Tripathi
Ankur Tripathi

Reputation: 472

The ContinueWith function is a method available on the task that allows executing code after the task has finished execution. In simple words it allows continuation.

Things to note here is that ContinueWith also returns one Task. That means you can attach ContinueWith one task returned by this method.

   Task<string> t = Task.Run(() => LongRunningOperation("Continuewith", 500));  
   t.ContinueWith((t1) =>  
   {  
      Console.WriteLine("Running..."); 
   });  

Upvotes: 1

Related Questions