Why Task does not start without Wait - c#

When I create a Task :
for (int i = 0; i < 5; i++)
{
// var testClient =
Task.Factory.StartNew(
() =>
{
TaskClient();
});
}
public static void TaskClient()
{
System.Console.WriteLine("--------------------");
}
But this does not start the Console Write Untill I wait for the task!!!
Task.Factory.StartNew(
() =>
{
TaskClient();
}).Wait();
Why do we need to call Wait , When I am already starting the thread using StartNew

#vcsjones has to be right. You don't see the result because program ended and window was closed.
I've tried your code and if I run the program from cmd, without debugger I can see the correct output. To make it a little more meaningful I've added another Console.WriteLine at the end of Main method:
for (int i = 0; i < 5; i++)
{
// var testClient =
Task.Factory.StartNew(
() =>
{
TaskClient();
});
}
Console.WriteLine("End of program execution.");
Returns:
End of program execution.
--------------------
--------------------
--------------------
--------------------
--------------------
As you can see, it works just fine.
If you want to wait with further execution untill all tasks are done, you can use Task.WaitAll static method:
var tasks = new Task[5];
for (int i = 0; i < 5; i++)
{
// var testClient =
tasks[i] = Task.Factory.StartNew(
() =>
{
TaskClient();
});
}
Task.WaitAll(tasks);

Related

Asynchronous tasks in C# console application combined with Windows.Forms

Let's say I have 10 tasks which should run simultaneously visualizing their progress using GUI. For simplicity let them be just counters 1 to 100. Main app should be console application. GUI controls should be generated on the fly.
Here's the code I've written:
static void Main(string[] args)
{
Enumerable.Range(0, 10).ToList().ForEach(x =>
frm.Controls.Add(new Label()
{
Left = 10,
Top = 22 * x,
}));
Thread mThread = new Thread(delegate ()
{
frm.ShowDialog();
});
mThread.SetApartmentState(ApartmentState.STA);
mThread.Start();
Jobs();
}
static void Jobs()
{
Task[] tasks = new Task[10];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = PayLoad(i);
}
Task.WaitAll(tasks);
}
static async Task PayLoad(int taskNumber)
{
Console.WriteLine($"Task {taskNumber} is starting...");
//await Task.Delay(1000);
for (int i = 1; i < 100; i++)
{
Console.WriteLine($"Task {taskNumber} - iteration {i} ");
Action act = delegate () { frm.Controls[taskNumber].Text = i.ToString(); };
frm.BeginInvoke(act);
await Task.Delay(1000);
}
}
The problem is the progress stops when all counters reach 1. If I comment the 2nd await the code completes but I can see it works synchronously. All the labels are filled one by one.
Am I missing something?

System.Threading.Thread.Sleep() freezes my code when clicking on a line

I created a method for writing a text slowly for a game.
The problem is, when the method is running and I select something with mouse in cmd window, the whole program freezes and when I press escape it continues. Is there something I can do so it won't happen? Can I use something different than System.Threading.Thread.Sleep() for my program to wait?
static void slowly(string sen)
{
for (int j=0; j<sen.Length-1; j++)
{
Console.Write(sen[j]);
System.Threading.Thread.Sleep(100);
}
Console.WriteLine(sen[sen.Length-1]);
System.Threading.Thread.Sleep(100);
}
The problem is that your sleep code is running on the "Main Thread" of your application. This means that your application can't really do anything else while it's in the .slowly() method.
You need to do something like what #vidstige shows, which is to have your .slowly() method run in another (helper) thread.
A more modern approach would be to:
static async Task slowly(string sen)
{
await Task.Run(() =>
{
for (int j = 0; j < sen.Length - 1; j++)
{
Console.Write(sen[j]);
System.Threading.Thread.Sleep(100);
}
Console.WriteLine(sen[sen.Length - 1]);
System.Threading.Thread.Sleep(100);
});
}
public static void Main(string[] args)
{
var slowlyTask = slowly("hello world");
//do stuff while writing to the screen
var i = 0;
i++;
//wait for text to finish writing before doing somethign else
slowlyTask.Wait();
//do another something after it's done;
var newSlowlyTask = slowly("goodbye");
newSlowlyTask.Wait();
}
PS: The amount of negative responses to this question is disappointing :(
static void slowly(string sen)
{
var thread = new System.Threading.Thread(() => {
for (int j=0; j<sen.Length-1; j++)
{
System.Console.Write(sen[j]);
System.Threading.Thread.Sleep(100);
}
System.Console.Write(sen[sen.Length-1]);
System.Threading.Thread.Sleep(100);
});
thread.Start();
}

Async Task with sync method call

I'm starting with the new .net 4.5 async programming and I found a situation like the code below: I have a sync method but I would like to make several calls and make it run in parallel. However, in this code, all the calls to the sync method runs with the id = 10 and I'm not sure why (probably I misunderstand something with this new approach :).
class Program
{
static void Main(string[] args)
{
var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
var foo = new Foo();
var fooTask = Task.Run(() => foo.FooNonAsyncMethod(i));
tasks.Add(fooTask);
}
tasks.ForEach(t => t.Wait());
Console.WriteLine("All Done!");
Console.ReadLine();
}
}
public class Foo
{
public void FooNonAsyncMethod(int id)
{
Console.WriteLine("Starting {0}", id);
Thread.Sleep(4000);
Console.WriteLine("Ending {0}", id);
}
}
// Output:
// Starting 10
// Starting 10
// Starting 10
// Starting 10
// Ending 10
// Starting 10
// Starting 10
// Ending 10
// Ending 10
// ...
That's because there is only 1 variable i and the lambda expressions bind on a variable and not a value.
You can fix this by using:
for (int i = 0; i < 10; i++)
{
int newI = i;
var foo = new Foo();
var fooTask = Task.Run(() => foo.FooNonAsyncMethod(newI));
tasks.Add(fooTask);
}
As #Yuriy mentioned, this answer has a lot more info on this particularity : Is there a reason for C#'s reuse of the variable in a foreach?

Long running Process using Task objects and a Monitor Thread

I am attempting to monitor a long running process. Right now the process created new Task objects for all the small pieces, but I need some way to monitor their progress to send status to a UI.
ExecutionContext ctx = new ExecutionContext()
{
Result = result,
LastCount = result.Values.Count
};
Task t = Task.Factory.StartNew(() =>
{
foreach (var dataSlice in dataObjects)
{
Task.Factory.StartNew(() =>
{
// Do Some Work
}, TaskCreationOptions.AttachedToParent);
}
});
ctx.ParentTask = t;
Task monitor = Task.Factory.StartNew( () =>
{
ctx.LastCount = ctx.Result.Values.Count;
}, TaskCreationOptions.LongRunning);
My problem, or perhaps question is, if I force my monitor task to wait (via a SpinWait or Sleep) will it possibly lock part of the Tasks created above it? I need the monitor to check status every now and then, but I don't want it's wait condition to kill another task that needs to run.
EDIT:
So I found an interesting approach that's very similar to what Hans suggested in the comments below. It comes in two pieces. One Task to happen multiple times in the middle, and one completion task to do the final clean-up. Still in testing, but it looks promising.
Here's what it looks like:
Task t = new Task(() =>
{
int i = 0;
for (int j = 0; j < 200; j++)
{
foreach (var session in sessions)
{
Task work = action.Invoke(SomeParameter);
if (i == 50 || i == 0)
{
work.ContinueWith(task => Task.Factory.StartNew(UpdateAction));
i = 1;
}
else
{
i++;
}
}
}
});
ctx.ParentTask = t;
t.ContinueWith(CompletionAction => Task.Factory.StartNew(() => CompleteExecution(SomeParameter)));
t.Start();

Task usually does not run

I am newbie to parallel programming. I write the basic code below but it doesnt run always as I excepted.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
Console.WriteLine ("End");
I usually could not get the result of the loop 8-9 out of 10 trials. Sometimes it prints the loop results, sometimes not. But I it always prints the Start and End. Whats happening at the behind side ? Why sometimes I could not get the result of loop from time to time ?
Thanks in advance,
Your program is terminating before the parallel loop gets a chance to print any output.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
Console.ReadLine();
Console.WriteLine("End");
Pause by waiting for input, and you'll see the loop run correctly.
Add a readline at the end. You will see the following:
Start
End
0
1
2
3
4
Console.WriteLine("Start");
Task task = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
});
Console.WriteLine("End");
Console.ReadLine();
You must tell your main thread to wait till your task is over.
Your "End" was being printed in most cases before the task thread executed. Use TaskContinuationOptions to tell the parent thread to wait for its tasks threads to complete.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
task.ContinueWith(ant =>
{
Console.WriteLine("End");
}, TaskContinuationOptions.NotOnFaulted| TaskContinuationOptions.AttachedToParent);
task.Wait();

Categories

Resources