I've just started learning C# and I'm trying to figure out threads.
So, I've made a two threads and I would like to stop one of them by pressing x.
So far when I press x it only shows on the console but it doesn't abort the thread.
I'm obviously doing something wronng so can someone please point out what I'm doing wrong? Thank you.
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//Creating Threads
Thread t1 = new Thread(Method1)
{
Name = "Thread1"
};
Thread t4 = new Thread(Method4)
{
Name = "Thread4"
};
t1.Start();
t4.Start();
Console.WriteLine("Method4 has started. Press x to stop it. You have 5 SECONDS!!!");
var input = Console.ReadKey();
string input2 = input.Key.ToString();
Console.ReadKey();
if (input2 == "x")
{
t4.Abort();
Console.WriteLine("SUCCESS! You have stoped Thread4! Congrats.");
};
Console.Read();
}
static void Method1()
{
Console.WriteLine("Method1 Started using " + Thread.CurrentThread.Name);
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Method1: " + i);
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine("Method1 Ended using " + Thread.CurrentThread.Name);
}
static void Method4()
{
Console.WriteLine("Method4 Started using " + Thread.CurrentThread.Name);
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Method4: " + i);
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine("Method4 Ended using " + Thread.CurrentThread.Name);
}
It looks like you have a extra Console.ReadKey(); before if (input2 == "x"), that extra read causes the program to stop and wait before going inside your if statement waiting for a 2nd key to be pressed.
Also input.Key returns a enum, when you do the to string on it the enum will use a capital X because that is what it is set to. Either use input.KeyChar.ToString() to convert it to a string or use
var input = Console.ReadKey();
if (input.Key == ConsoleKey.X)
To compare against the enum instead of a string.
I also recommend you read the article "How to debug small programs", debugging is a skill you will need to learn to be able to write more complex programs. Stepping through the code with a debugger you would have seen input2 was equal to X so your if statement was
if ("X" == "x")
which is not true.
Related
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 made a program which has 5 questions, it reads the users answer and lets them know if they were correct or not, if they were incorrect the user is forced to begin the 5 questions again. I added a count increment so that the program can tell the user the number of times it took to complete the quiz and i also added a "questions left" left feature which will tell you how many questions were left. as of now the code is all in one class and not separated into methods and uses the old "go to" loops. How would I go about changing the loops to a more modern code and how would I program it to use more methods for organising it, also the questions left feature works if the user gets every question correct but when the user gets a question wrong and restarts the questions left feature doesn't output the correct number.
here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace practicePro
{
class Program
{
public static void Main(string[] args)
{
/*----------------------------------------Declaration----------------------------------------- */
string q1, q2, q3, q4, q5;
int questionsLeft;
questionsLeft = 5;
/*----------------------------------------TITLE----------------------------------------- */
Console.WriteLine("Welcome to the Ultimate quiz!");
Console.WriteLine();
/*----------------------------------------QUESTION 1----------------------------------------- */
int count = 0;
start:
count++;
Console.WriteLine("What programming language has a snake as its name" + " questions left: " + questionsLeft );
Console.WriteLine();
q1 = Console.ReadLine();
q1 = q1.ToUpper();
if (q1 == "PYTHON")
{
Console.WriteLine();
Console.WriteLine("Well Done, you may move on to the next question");
questionsLeft--;
}
else
{
Console.WriteLine("Sorry you got the answer wrong, you have to start again");
goto start;
}
Console.WriteLine();
/*----------------------------------------QUESTION 2----------------------------------------- */
Console.WriteLine("What is the age range to qualify for an apprenticeship in the uk? Please type in the following format xx-yy" + " questions left: " + questionsLeft);
Console.WriteLine();
q2 = Console.ReadLine();
if (q2 == "16-24")
{
Console.WriteLine();
Console.WriteLine("Well Done, you may move on to the next question");
questionsLeft--;
}
else
{
Console.WriteLine("Sorry you got the answer wrong, you have to start again");
goto start;
count++;
}
Console.WriteLine();
/*----------------------------------------QUESTION 3----------------------------------------- */
Console.WriteLine("Is HTML a programming language (Yes or No)" + " questions left: " + questionsLeft);
Console.WriteLine();
q3 = Console.ReadLine();
q3 = q3.ToUpper();
if (q3 == "NO")
{
Console.WriteLine();
Console.WriteLine("Well Done, you may move on to the next question");
questionsLeft--;
}
else
{
Console.WriteLine("Sorry you got the answer wrong, you have to start again");
goto start;
count++;
}
Console.WriteLine();
/*----------------------------------------QUESTION 4----------------------------------------- */
Console.WriteLine("In JavaScript, What are the 2 charecters used to symbolise a single line comment?" + " questions left: " + questionsLeft);
Console.WriteLine();
q4 = Console.ReadLine();
if (q4 == "//")
{
Console.WriteLine();
Console.WriteLine("Well Done, you may move on to the next question");
questionsLeft--;
}
else
{
Console.WriteLine("Sorry you got the answer wrong, you have to start again");
goto start;
count++;
}
Console.WriteLine();
/*----------------------------------------QUESTION 5----------------------------------------- */
Console.WriteLine("500 < 600 && 700 < 600");
Console.WriteLine();
Console.WriteLine("Is the above statement true or false ?" + " questions left: " + questionsLeft);
Console.WriteLine();
q5 = Console.ReadLine();
q5 = q5.ToUpper();
if (q5 == "FALSE")
{
Console.WriteLine();
Console.WriteLine("Well Done, you may move on to the next question");
Console.WriteLine();
Console.WriteLine("Congratulations You have passed the quiz!");
questionsLeft--;
}
else
{
Console.WriteLine("Sorry you got the answer wrong, you have to start again");
goto start;
}
Console.WriteLine();
Console.WriteLine("you took " + count + " time(s) to complete the quiz");
}
}
}
You can create a Question class, which will contain a text (question), and the right answer.
In your Main method, you can create and initialize the list of questions :
List<Question> questions = new List<Question>() {
new Question("What programming language has a snake as its name ?", "PYTHON"),
new Question(...),
...
}
Then you can create your workflow algorithm. Example :
Console.WriteLine("Welcome to the Ultimate quiz!");
Console.WriteLine();
int count = 0;
while(questions.Count > 0) {
Console.WriteLine(question.First().Text + " (question left: " + questions.Count + ")");
string answer = Console.ReadLine();
if (answer == questions.First().Answer)
{
Console.WriteLine();
Console.WriteLine("Well Done, you may move on to the next question");
questions.RemoveAt(0);
}
else
{
Console.WriteLine("Sorry you got the answer wrong, you have to start again");
count++;
}
}
Console.WriteLine();
Console.WriteLine("you took " + count + " time(s) to complete the quiz");
You can even create a Ask() method in the Question class, which will ask the question and analyze the answer (this method must take in parameter the number of question left, to display it).
Writing methods that contain logic is easy:
// Without extra method
class Program
{
static void Main(string[] args)
{
int a = 1;
int b = 2;
int c = a + b;
}
}
would turn into
// With extra method
class Program
{
static void Main(string[] args)
{
int a = 1;
int b = 2;
int c = Add(a, b);
}
static int Add(int num1, num2)
{
return num1 + num2;
}
}
Basics about methods:
They always have an access modifier (public or private, if none is given, it's private in C#
They always have a return type (in this case: int)
They always have a name (in this case: Add)
They can take parameters (in this case: num1 and num2)
If the return type is not void they always need a return statement in every code path
In order to loop until the player has answered every question correctly, you could make the asking method a bool type and as long as it returns false (which should happen every time the player answers wrong), a Player class calls the asking method.
// Quiz being the asking method
while(!Quiz())
{
// wrongAnswers being the counter for failed attempts
wrongAnswers++;
}
Console.WriteLine("Success!");
This will call the Quiz() method, which will then ask the player its 5 questions (which can, as Paul DS stated, be stored in a seperate class) and if it returns false (which means the player has answered one question wrong), it adds 1 to wrongAttempts, before calling it again. If it returns true, wrongAnswers is not incremented by 1 and "Success!" is shown.
I created a program in C# (Console Application), which prompts the user to enter the answer to "2+2=?", if its right a message pops up "Well done", if not then "Please try again". What I am trying to do is make the program tell the user how many guesses/attempts they have made before getting the correct answer.
This is what I have done so far
class Program
{
public static int correct_answer, counter, user_answer, counterUpdated;
static void Main(string[] args)
{
correct_answer = 4;
do
{
counter = 1;
counterUpdated = counter++;
Console.WriteLine("2+2= ?");
user_answer = Convert.ToInt32(Console.ReadLine());
if (user_answer != correct_answer)
{
Console.Clear();
Console.WriteLine("Wrong, try againg" + " this is your " + counterUpdated + " try.");
}
} while (user_answer != correct_answer); // The code will keep looping until the user prompts the correct answer
Console.Clear();
Console.WriteLine("Well Done! you did it in this amount of guesses " + counterUpdated);
Console.ReadLine();
}
}
If someone could tell me how to make the counter thing work, that would be great.
You always set counter to 1 at the start of the loop, then immediately counterUpdated = counter++; (which is a bit odd anyway...).
Just do it with one counter that you initialize outside the loop and increment inside the loop.
int guessNumber = 0;
do {
guessNumber++;
// ...
Tweaked a bit, and this should work :)
class Program
{
public static int correct_answer, counter, user_answer;
static void Main(string[] args)
{
correct_answer = 4;
counter = 0;
do
{
counter++;
Console.WriteLine("2+2= ?");
user_answer = Convert.ToInt32(Console.ReadLine());
if (user_answer != correct_answer)
{
Console.Clear();
Console.WriteLine("Wrong, try againg" + " this is your " + counter+ " try.");
}
} while (user_answer != correct_answer); // The code will keep looping until the user prompts the correct answer
Console.Clear();
Console.WriteLine("Well Done! you did it in this amount of guesses " + counter);
Console.ReadLine();
}
}
What i did was i removed the counterUpdated variable and had the counter variable do all the counting work :)
Hope it helped :)
I'm trying to make a test to see if someone has certain skills.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class timerup
{
public bool timeup = false;
}
class Program
{
public static void timer()
{
for (int i = 1; i < 3; i++)
{
System.Threading.Thread.Sleep(1000);
if (i == 5)
{
object a;
a = true;
a = new timerup();
timerup ClassRef;
ClassRef = (timerup)a;
ClassRef.timeup = true;
}
}
}
static void Main(string[] args)
{
Console.Title = "The Secret Agent Test";
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Welcome, agent. This is the test to see if\nyou are good enough to be a full member of the OT Secret Agency.");
Console.WriteLine("Do you want to continue? [Y/N]");
string cont = Console.ReadLine();
if (cont == "y" || cont =="Y")
{
Console.Clear();
Console.WriteLine("Let's continue the test.");
Console.WriteLine("Crack the password:");
Console.WriteLine("Username: IDIOT_NOOB1337\nPROFILE: Likes memes such as doge.\nIs an elitist (Over the things he likes)\nOnly uses the word idiot as an insult");
Console.WriteLine("Password:");
string pass1 = Console.ReadLine();
if (pass1 == "AnyoneWhoDoesn'tLikeDogeIsAnIdiot" || pass1 == "anyonewhodoesn'tlikedogeisanidiot")
{
Console.WriteLine("Account accessed.");
Console.WriteLine("Stage 1 Complete.");
Console.WriteLine("Loading next level...");
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Level 2 loaded.");
System.Threading.Thread.Sleep(1000);
Console.Clear();
Console.WriteLine("Nice. You certainly have skill. But this test.... determines speed of mind.");
System.Threading.Thread.Sleep(2500);
Console.Clear();
Console.WriteLine("You only have two seconds to answer the next question. Press any key when ready.");
Console.ReadKey();
Console.Clear();
Console.WriteLine("What is 12x12?!"); // QUESTION
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(timer)); // SUCH COMPLEX CODE FOR A TIMER... WTF.
string product = Console.ReadLine();
object b;
b = true;
b = new timerup();
timerup ClassRef;
ClassRef = (timerup)b;
bool timerthing = ClassRef.timeup;
if (product != "144" || timerthing == true)
{
Console.WriteLine("Sorry, you are incorrect. Restart the test again.");
System.Threading.Thread.Sleep(2000);
Console.Clear();
System.Environment.Exit(-1);
}
else
{
Console.WriteLine("Impressive. Your mind is fast, too. Well, be prepared for the next test. Pressure.");
}
}
}
}
}
}
The thread does not execute; I suspect it is because of the string product = Console.ReadLine(); bit. The second question of this quiz was 12x12, and you have 2 seconds to answer, except the thread that counted the two seconds wasn't executed... Why...? And if you know, how would I fix it?
You only created a thread. You should also start it.
System.Threading.Thread t = new System.Threading.Thread(timer);
t.Start();
Just wrote this down as an example of how you can check for how long time has passed without using a thread.
bool isInTime = false;
var start = DateTime.Now;
Console.WriteLine("answer this in 5 seconds, what is 2x2");
var answer = Console.ReadLine();
if ((DateTime.Now - start).TotalSeconds <= 5)
isInTime = true;
if (isInTime && answer == "4")
Console.WriteLine("Good job you are now an agent");
else
Console.WriteLine("To slow and too dumb");
Console.ReadKey();
Stopwatch is another alternative: http://www.dotnetperls.com/stopwatch
If you really want threads (which are overkill for this problem) there are some good examples here: https://msdn.microsoft.com/en-us/library/ts553s52(v=vs.110).aspx
The two answers are on the spot, so let me just add how you can create a timer that's not as convoluted :)
var timeIsUp = false;
var timer = new Timer(_ => { timeIsUp = true; }, null, 5000, Timeout.Infinite);
But in general, #JensB is absolutely right - using multi-threading should be the last option. It's very hard to handle multi-threading properly, so avoiding it is a pretty decent strategy. The Timer example I've shown is also multi-threaded - the callback on the timer will occur on a different thread. This introduces synchronization issues, but they shouldn't be too painful for a simple case like this. To improve upon this, you'd at least want to ensure the local is updated safely:
var syncObject = new object();
var timeIsUp = false;
var timer = new Timer(_ => { lock (syncObject) { timeIsUp = true; } }, null, 5000,
Timeout.Infinite);
var answer = Console.ReadLine();
lock (syncObject)
{
if (timeIsUp) ...
}
Finally, using Thread manually is completely unnecessary nowadays. It's much easier to use Tasks for concurrency and multi-threading. For example:
var timerTask = Task.Delay(5000);
var answer = Console.ReadLine();
if (timerTask.IsCompleted) Console.WriteLine("Too late");
The best option IMO would be to use proper asynchronous APIs - sadly, the .NET Console class doesn't have those. As silly as it is, it seems that this is a pretty decent option:
void Main()
{
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(2));
var task = Task.Run(() => ReadLineFromConsole(cts.Token));
task.Wait(cts.Token);
if (task.IsCanceled)
{
Console.WriteLine("Too slow!");
return;
}
var result = task.Result;
if (result != "144")
{
Console.WriteLine("Wrong!");
return;
}
// Continue
}
public string ReadLineFromConsole(CancellationToken token)
{
var buffer = new StringBuilder();
int ch;
while (!token.IsCancellationRequested)
{
Console.In.Peek();
token.ThrowIfCancellationRequested();
ch = Console.In.Read();
if (ch == -1) return buffer.Length > 0 ? buffer.ToString() : null;
if (ch == '\r' || ch == '\n')
{
if (ch == '\r' && Console.In.Peek() == '\n') Console.In.Read();
return buffer.ToString();
}
buffer.Append((char)ch);
}
token.ThrowIfCancellationRequested();
// Shouldn't be reached, but the compiler doesn't know that.
return null;
}
The interesting point about this approach is that I can exit the application (and abort the input) even if the user doesn't press enter. It also allows you to tie together complex work flows using await, although that's slightly tricky in a console application.
The helper method ReadLineFromConsole actually works the same as the usual ReadLine method, however, it also checks for cancellation, and to prevent it from "stealing" data from later ReadLine calls, it will Peek first. This doesn't make it thread-safe - you still shouldn't using multiple readlines at the same time from different threads. But it does mean that we can ignore the output when it finally comes. Bear in mind that the thread will be waiting all this time until a console input comes - do not use this to launch multiple simultaneous requests without ensuring there's some input on the way eventually (e.g. using the usual Console.ReadLine in between the ReadLineFromConsole calls etc.).
Some refactoring to your code and solution to your problem :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace ConsoleApplication2
{
class Program
{
static void WriteText(params string[] lines) { WriteText(0, lines); }
static void WriteText(double delaySecs, params string[] lines)
{
for (int i = 0; i < lines.Length; i++) Console.WriteLine(lines[i]);
if (delaySecs > 0) Thread.Sleep(TimeSpan.FromSeconds(delaySecs));
}
static void Main(string[] args)
{
Console.Title = "The Secret Agent Test";
Console.ForegroundColor = ConsoleColor.Green;
WriteText("Welcome, agent. This is the test to see if\nyou are good enough to be a full member of the OT Secret Agency.", "Do you want to continue? [Y/N]");
var readk = Console.ReadKey();
if (readk.Key == ConsoleKey.Y || readk.Key == ConsoleKey.N)
{
Console.Clear();
WriteText("Let's continue the test.\n", "Crack the password:\n", "Username: IDIOT_NOOB1337\nPROFILE: Likes memes such as doge.",
"Is an elitist (Over the things he likes)", "Only uses the word idiot as an insult", "Password:");
string pass1 = Console.ReadLine();
if (pass1 != "AnyoneWhoDoesn'tLikeDogeIsAnIdiot" && pass1 != "anyonewhodoesn'tlikedogeisanidiot") return;
WriteText(2, "Account accessed.", "Stage 1 Complete.", "Loading next level...");
WriteText(1, "Level 2 loaded.");
Console.Clear();
WriteText(2.5, "Nice. You certainly have skill. But this test.... determines speed of mind.");
Console.Clear();
Console.WriteLine("You only have two seconds to answer the next question. Press any key when ready.");
Console.ReadKey();
Console.Clear();
Console.WriteLine("What is 12x12?!"); // QUESTION
int allowedTime = 2 * 1000; // time allowed
new Thread(() =>
{
Stopwatch s = new Stopwatch();
s.Start();
while (s.ElapsedMilliseconds < allowedTime) { }
WriteText(2, "Sorry, you're too late. Restart the test again.");
Console.Clear();
Environment.Exit(-1);
}).Start();
string product = Console.ReadLine();
if (product == "144") Console.WriteLine("Impressive. Your mind is fast, too. Well, be prepared for the next test. Pressure.");
WriteText(2, "Sorry, you are incorrect. Restart the test again.");
Console.Clear();
}
}
}
}
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
}