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();
}
Related
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?
I've been trying to implement multi threading which looks something like this:
static void Main(string[] args)
{
List<Task> tskList = new List<Task>();
for (int i = 0; i < 100; i++)
{
Task taskTemp = new Task(() => { Display(i); });
taskTemp.Start();
tskList.Add(taskTemp);
//Thread.Sleep(10);
}
Task.WaitAll(tskList.ToArray());
}
public static void Display(int value)
{
Thread.Sleep(1000);
Console.WriteLine(value);
}
Without the Thread.Sleep(10) part, I get output printed as 100 times "100" instead of 0 to 99 which I'm getting with that sleep time of 10 ms.
My guess is that this could be happening because of the time required to schedule the thread by the system and by the time the thread is about to actually start, the value has reached 100.
If I put enough wait time (say 1000 ms instead of 10), will it be guaranteed to not have this problem? Or should I suspect that the system may take even more time to schedule the thread when CPU utilization is too much? What is the best way to solve this problem?
Thanks in advance for any inputs!
you should add a local variable to hold 'i', such as :
for (int i = 0; i < 100; i++)
{
var t = i;
Task taskTemp = new Task(() => { Display(t); });
taskTemp.Start();
tskList.Add(taskTemp);
//Thread.Sleep(10);
}
Just make a copy of "i" to "i1" and use it as local variable. "i" is always changed, thats why you get 100 100 100....:
private static void Main(string[] args)
{
var tskList = new List<Task>();
for (var i = 0; i < 100; i++)
{
var i1 = i;
var taskTemp = new Task(() => { Display(i1); });
taskTemp.Start();
tskList.Add(taskTemp);
}
Task.WaitAll(tskList.ToArray());
}
public static void Display(int value)
{
Thread.Sleep(1000);
Console.WriteLine(value);
}
I'm new to programming and currently I'm trying to learn c#. Here is my question:
I have this following piece of code:
static void Main()
{
string loading = "LOADING...";
for (int i = 0; i < 5; i++)
{
foreach (var letter in loading)
{
Console.Write("{0}", letter);
Thread.Sleep(250);
}
Console.Clear();
Console.Write("\r");
}
for (int k = 0; k <= 100; k++)
{
Console.Write("\r{0}%", k);
Thread.Sleep(150);
}
}
I am trying to find a way to execute these two for loops simultaneously. I want to keep re-writing LOADING on the console and under it to print the percentage from 1 to 100. Right now the second for loop runs after the first quits. Is it possible to make them run at the same time? I have been trying to find an answer for a few hours now, but with no luck so far.
Thanks!
As krillgar noted you can use Tasks to run each loop independently. Something like this:
string loading = "LOADING...";
var loadingTask = Task.Run(() =>
{
for (int i = 0; i < 5; i++)
{
foreach (var letter in loading)
{
Console.Write("{0}", letter);
Thread.Sleep(250);
}
Console.Clear();
Console.Write("\r");
}
});
var pocTask = Task.Run(() =>
{
for (int k = 0; k <= 100; k++)
{
Console.Write("\r{0}%", k);
Thread.Sleep(150);
}
});
Task.WaitAll(loadingTask, pocTask);
Please note however it'll not work as you would expect( first line with LOADING... and second with percentage). That would require some synchronization of displayed messages between those loops and I think that's whole another story and not in the scope of the answer to your question.
There is more to this challenge than just running the code in two threads. When multiple threads are attempting to write to the console simultaneously, you are likely to end up with race conditions, where one thread starts writing in the middle of another thread's output.
To protect against this, you need to enforce critical sections, which are regions of your code where only one thread can execute at any time. These would generally consist of:
// Critical section
lock (syncLock)
{
Console.SetCursorPosition(x, y);
Console.Write(yourText);
}
Thread.Sleep(yourDelay);
Here is the full code:
// Dummy object to serve as mutual-exclusion lock when synchronizing threads.
private static readonly object syncLock = new object();
public static void Main(string[] args)
{
// Run two anonymous functions in parallel,
// then wait for both to complete.
Parallel.Invoke(
// Anonymous function for printing "LOADING..."
() =>
{
const string loading = "LOADING...";
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < loading.Length; j++)
{
// Critical section
lock (syncLock)
{
Console.SetCursorPosition(j, 0);
Console.Write("{0}", loading[j]);
}
Thread.Sleep(250);
}
// Critical section
lock (syncLock)
{
Console.SetCursorPosition(0, 0);
Console.Write("\r ");
}
Thread.Sleep(250);
}
},
// Anonymous function for printing "x%"
() =>
{
for (int k = 0; k <= 100; k++)
{
// Critical section
lock (syncLock)
{
Console.SetCursorPosition(0, 1);
Console.Write("\r{0}%", k);
}
Thread.Sleep(150);
}
});
}
}
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);
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();