Threads don't start as expected

I am trying to do 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 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 fails; I suspect this is because of the bit string product = Console.ReadLine();

. The second question of this quiz was 12x12 and you have 2 seconds to answer, except that the thread that was counting two seconds was not executed ... Why ...? And if you know how can I fix this?

+3


source to share


4 answers


Some refactorings for 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 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();                
            }
        }
    }
}

      

0


source


You have only created a stream. You must also run it.



System.Threading.Thread t = new System.Threading.Thread(timer);
t.Start();

      

+6


source


Just wrote it down as an example of how you can check how much time has passed without using a stream.

        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 streams (which are overkill for this problem), there are some good examples here: https://msdn.microsoft.com/en-us/library/ts553s52(v=vs.110).aspx

+5


source


Two answers are in place, so let me add how you can create a timer that isn't that confusing. :)

var timeIsUp = false;
var timer = new Timer(_ => { timeIsUp = true; }, null, 5000, Timeout.Infinite);

      

But overall, @JensB is absolutely right - using multithreading should be the last option. It is very difficult to handle multithreading, so avoid it as a pretty decent strategy. The example Timer

I showed is also multithreaded - the timer callback will happen on a different thread. This introduces timing problems, but they shouldn't be too painful for a simple case like this. To improve on this, you at least want to ensure that your local location 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, Thread

manual use is completely unnecessary these days. Much easier to use Task

for concurrency and multithreading. For example:

var timerTask = Task.Delay(5000);

var answer = Console.ReadLine();

if (timerTask.IsCompleted) Console.WriteLine("Too late");

      

Your best bet IMO would be to use the correct asynchronous APIs - unfortunately the .NET class Console

doesn't have those. As silly as it sounds, this seems like 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 typing) even if the user does not press enter. It also allows you to bind complex workflows using await

, although this is a bit tricky in a console application.

The helper method ReadLineFromConsole

actually works the same as the normal method ReadLine

, however it also checks for cancellation and prevents data from being "stolen" from subsequent calls ReadLine

, it will be the Peek

first. This does not make it thread safe - you shouldn't use multiple read lines at the same time from different threads anyway. But that means we can ignore the conclusion when it finally arrives. Keep in mind that the thread will wait all this time before entering the console - don't use this to run multiple concurrent requests without guaranteeing there some input at the end of the path (for example, using normal Console.ReadLine

between ReadLineFromConsole

calls, etc.).

+2


source







All Articles