im new to C# and i was trying to figure out async and await . for practice i was trying to start method 1 in which method 2 is called twice . method 2 takes a value and increases it by 1 each 200 ms . instead of running method 2 the program ends after the first line of method 1 .
static void Main(string[] args)
{
Method1();
}
static int Method2(int x)
{
for (int i = 0; i < 10; i++)
{
x += 1;
Console.WriteLine(x);
Thread.Sleep(200);
}
Console.WriteLine("final" + " " + x + " " + Thread.CurrentThread.ManagedThreadId);
return x;
}
static async Task Method1()
{
Console.WriteLine("1 running");
int result1 = await Task.Run(() => Method2(0));
int result2 = await Task.Run(() => Method2(result1));
Thread.Sleep(1000);
Console.WriteLine("result " + result2 * 2);
}
what am i doing wrong here ?
When calling Method() you aren't waiting on it. It returns a task object that is not acted upon, and then Main() dutifully returns, which ends the program.
You can do this in Main():
public static void Main() {
Method1().GetAwaiter().GetResult();
}
Or use async Main() instead:
public static async Task Main() {
await Method1();
}
Related
This question already has answers here:
How to delay 'hot' tasks so they can processed in a set order
(2 answers)
Closed 4 years ago.
I need to first create new task then do some remaining work and then start the task that works with its result.
Simplified example:
static int value;
static async Task work1()
{
do
{
int i;
for (i = 0; i < 10000000; i++) {} // some calculations
Console.WriteLine("result1: " + value + " i: " + i);
await Task.Delay(2000).ConfigureAwait(false);
} while (condition);
}
static async Task work2()
{
do
{
int i;
for (i = 0; i < 10000000; i++) {} // some calculations
Console.WriteLine("result2: " + value + " i: " + i);
await Task.Delay(2000).ConfigureAwait(false);
} while (condition);
}
static void Main(string[] args)
{
Task task;
int tempvalue = 100;
if (condition1)
{
tempvalue *= 10;
task = new Task(() => work1());
} else
{
tempvalue -= 5;
task = new Task(() => work2());
}
if (tempvalue > 100)
{
value = 5;
} else
{
value = tempvalue;
}
task.Start();
// immediately do remaining work
}
this code does exactly what I need but compiler shows following warning:
Warning CS4014 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
on line:
Task task = new Task(() => work());
should I rather use it like so? Is there any difference?
Task task = new Task(async () => await work());
This is not a duplicate of How to delay 'hot' tasks so they can processed in a set order because after task.Start(); it should do remaining work immediately.
Func<Task> f = () => work();
// do stuff
f(); // blocks thread until work1() or work2() hits await
// do remaining work
The async keyword means that the task within your task is asynchronous and using await will mean that you want to wait for the method work to finish.
You could also use Task.Wait() in order to wait for the method to finish it's execution.
But using async await is the better way to do it because it's not blocking the main thread.
I am trying various options on working with threads. I wrote the code below, but it does not work as expected. How can I fix the code, so that the main function will correctly display the product?
using System;
using System.Threading;
namespace MultiThreads
{
class Program
{
static int prod;
public static void Main(string[] args)
{
Thread thread = new Thread(() => Multiply(2, 3));
thread.Start();
for(int i = 0; i < 10; i++) { // do some other work until thread completes
Console.Write(i + " ");
Thread.Sleep(100);
}
Console.WriteLine();
Console.WriteLine("Prod = " + prod); // I expect 6 and it shows 0
Console.ReadKey(true);
}
public static void Multiply(int a, int b)
{
Thread.Sleep(2000);
prod = a * b;
}
}
}
Ignoring the fact that you should be using non-blocking tasks, volatile properties and other coroutine principals, the immediate reason your program does not work as intended is because you didn't re-join the child thread back into the parent. See Join
Without the join, the Console.WriteLine("Prod = " + prod); occurs before the assignment prod = a * b;
static int prod;
static void Main(string[] args)
{
Thread thread = new Thread(() => Multiply(2, 3));
thread.Start();
for (int i = 0; i < 10; i++)
{ // do some other work until thread completes
Console.Write(i + " ");
Thread.Sleep(100);
}
thread.Join(); // Halt current thread until the other one finishes.
Console.WriteLine();
Console.WriteLine("Prod = " + prod); // I expect 6 and it shows 0
Console.ReadKey(true);
}
public static void Multiply(int a, int b)
{
Thread.Sleep(2000);
prod = a * b;
}
I'm trying to use async click event:
private async void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " click_begin");
await changeProgressBarAsync(ProgresBar_mainLoad);
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " click_end");
}
public Task changeProgressBarAsync(ProgressBar pb)
{
return Task.Factory.StartNew(() =>
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " task");
int count = 100;
while (count-- > 0)
{
pb.Dispatcher.Invoke(() =>
{
pb.Value += 1;
});
Thread.Sleep(10);
}
});
}
Following the async-await C# logic, lines
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " task");
and
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " click_end");
should show equal thread Id,
but this program show me
1 click_begin
5 task
1 click_end
So why it happens?
I did same test in console app
static void Main(string[] args)
{
TestClick();
Console.ReadKey();
}
public static async void TestClick()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is TestClick1");
await Worker();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is TestClick2");
}
public static Task Worker()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is Task");
});
}
And it show me
1 it is TestClick1
3 it is Task
3 it is TestClick2
You're explicitly starting a new task using Task.Factory.StartNew(). That's almost always going to run in a non-UI thread.
The async/await way of doing this is not to start a new task on a different thread, not to use the dispatcher, and not to use Thread.Sleep, but Task.Delay instead. Then you'd have:
public async Task ChangeProgressBarAsync(ProgressBar pb)
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " task");
int count = 100;
while (count-- > 0)
{
pb.Value++;
await Task.Delay(10);
}
}
No extra threads anywhere.
In your console app you're seeing different threads because a console app doesn't have a synchronization context - there's nothing to make the continuation execute in the same thread as the thread that originally awaited.
I'm trying to find a way of causing the program to not pause but for their to be a delay to execute certain tasks. I.e. I am trying to delay outputting 'Hello' to the console for 10 seconds for example, but the program will continue to execute the rest of the program.
Using TPL:
static void Main(string[] args)
{
Console.WriteLine("Starting at " + DateTime.Now.ToString());
Task.Run(() =>
{
Thread.Sleep(10000);
Console.WriteLine("Done sleeping " + DateTime.Now.ToString());
});
Console.WriteLine("Press any Key...");
Console.ReadKey();
}
output:
Starting at 2/14/2017 3:05:09 PM
Press any Key...
Done sleeping 2/14/2017 3:05:19 PM
just note that if you press a key before 10 seconds, it will exit.
There are 2 typical ways to simulate a delay:
an asynchronous task-like: Task.Delay
or a blocking activity: Thread.Sleep
You seem to refer to the first situation.
Here it is an example
public static void Main(string[] args)
{
Both();
}
static void Both() {
var list = new Task [2];
list[0] = PauseAndWrite();
list[1] = WriteMore();
Task.WaitAll(list);
}
static async Task PauseAndWrite() {
await Task.Delay(2000);
Console.WriteLine("A !");
}
static async Task WriteMore() {
for(int i = 0; i<5; i++) {
await Task.Delay(500);
Console.WriteLine("B - " + i);
}
}
Output
B - 0
B - 1
B - 2
A !
B - 3
B - 4
Start a new thread:
Task.Factory.StartNew(new Action(() =>
{
Thread.Sleep(1000 * 10); // sleep for 10 seconds
Console.Write("Whatever");
}));
You could use a combination of Task.Delay and ContinueWith methods:
Task.Delay(10000).ContinueWith(_ => Console.WriteLine("Done"));
You could use 'Thread.Sleep(10000);'
See:
https://msdn.microsoft.com/en-us/library/d00bd51t(v=vs.110).aspx
I wrote a small programm which prints "x", then "+", then again "x" and so on.
The idea was to make it run in two threads so that the first thread prints "x" and the second prints "+". The output looks like this:
"x" -> Thread number 1
"+" -> Thread number 2
"x" -> Thread number 1enter code here
"+" -> Thread number 2
and so on..
What I wrote seems to work fine but it seems to me it is written in
very old-fashioned way:
public class Example
{
private static int count = 10;
private static int i = 0;
private static bool isOneActive = false;
private static void Run1(object o)
{
string s = o as string;
while(true)
{
if (!isOneActive)
{
Console.WriteLine("Hello from thread number: " +
Thread.CurrentThread.ManagedThreadId + " -> " + s);
isOneActive = true;
if (i++ > count) break;
}
}
}
private static void Run2(object o)
{
string s = o as string;
while(true)
{
if (isOneActive)
{
Console.WriteLine("Hello from thread number: " +
Thread.CurrentThread.ManagedThreadId + " -> " + s);
isOneActive = false;
if (i++ > count) break;
}
}
}
static void Main()
{
Thread t1 = new Thread(Run1);
Thread t2 = new Thread(Run2);
t1.Start("x");
t2.Start("+");
}
I know that now .NET has a lot of instruments for thread synchronization as for example ManualResetEvent class and Task library. So how could we write the same programm using ManualResetEvent class? Is it possible at all?
Your code isn't only old fashioned, it is very inefficient. It spins for no reason doing nothing but waiting; this is called Busy wait should be avoided whenever possible.
Better approach is to use Waithandles as noted in comments.
A naive implementation with very little change in your code will look something like the following.
public class Example
{
private static int count = 10;
private static int i = 0;
private static AutoResetEvent firstEvent = new AutoResetEvent(true);
private static AutoResetEvent secondEvent = new AutoResetEvent(false);
private static void Run1(object o)
{
string s = o as string;
while (true)
{
firstEvent.WaitOne();
Console.WriteLine("Hello from thread number: " + Thread.CurrentThread.ManagedThreadId + " -> " + s);
secondEvent.Set();
if (Interlocked.Increment(ref i) > count)
break;
}
}
private static void Run2(object o)
{
string s = o as string;
while (true)
{
secondEvent.WaitOne();
Console.WriteLine("Hello from thread number: " + Thread.CurrentThread.ManagedThreadId + " -> " + s);
firstEvent.Set();
if (Interlocked.Increment(ref i) > count)
break;
}
}
static void Main()
{
Thread t1 = new Thread(Run1);
Thread t2 = new Thread(Run2);
t1.Start("x");
t2.Start("+");
}
}
Note that firstEvent is instantiated with the initialState flag set to true which means that first thread doesn't waits initially.
Consider this example (fiddle):
static void Main(string[] args)
{
var console = new object();
int i = 0;
Task.Run(() =>
{
lock (console)
while (i++ < 10)
{
Console.Write(i);
Monitor.Pulse(console);
Monitor.Wait(console);
}
});
Task.Run(() =>
{
lock (console)
while (i < 10)
{
Console.Write('+');
Monitor.Pulse(console);
Monitor.Wait(console);
}
});
Console.ReadLine(); // Task.WaitAll might be better, remove for fiddle
}