Arjun
Arjun

Reputation: 1069

Console issue in .Net

I am just learning how to work with threading mechanism in C#. I took a example from msdn and altered it to design a simple game like this. But the problem is the while loop in DoWork method is reading keys even before DoWork Method is called from main program. I,e. When you run the program before "Go:" appears on the screen if you type some thing while loop in DoWork method is reading keys. But control should be passed to while loop after printing "Go:" on screen, Right. Can someone kindly explain me why it is happening like this. Thank You.

 public class Worker    
{
  ConsoleKeyInfo cki;  
  StringBuilder sb = new StringBuilder();
  bool f = true;

// This method will be called when the thread is started.
public void DoWork()
{
    Console.SetCursorPosition(49, 8);
    Console.Write("Go:");
    Console.SetCursorPosition(53, 8);

    while (!_shouldStop)
    {         
       cki = Console.ReadKey(true);
       if (f == true && (65 <= Convert.ToInt32(cki.Key) && Convert.ToInt32(cki.Key) <= 90))
       {
           Console.Write(cki.Key.ToString());               
           sb.Append(cki.Key.ToString());
       }  
    }
    while (true)
    {
        if (cki.Key.ToString() == "Enter") break;
        cki = Console.ReadKey(true);
        if (cki.Key.ToString() == "Enter") break;
    }
}
public void RequestStop(string word)
{
    _shouldStop = true;
    f =false;
    Console.WriteLine();
    Console.SetCursorPosition(44, 10);
    Console.WriteLine("- TIME OUT -");
    Console.SetCursorPosition(46, 12);
    if (sb.ToString() == word.ToUpper())
    {
        Console.WriteLine("CORRECT !");
        Console.SetCursorPosition(42, 13);
        Console.WriteLine("CONGRATULATIONS");
    }
    else { Console.SetCursorPosition(47, 12); Console.WriteLine("WRONG !"); }
    Console.SetCursorPosition(40, 15);
    Console.WriteLine("Press [Enter] to quit");
    Console.CursorVisible = false;
}

 private volatile bool _shouldStop;

}

public class WordPlay
{
  static void Main()
  {
    Console.SetBufferSize(100,50);
    Console.SetWindowSize(100,50);
    string[] words = { "angstrom", "abacinate", "abactinal", "abandoned", "Babesiidae", "babirussa", "Babylonian", "bacchantic", "cabassous", "cableway" };
    string word="";      
    Random randObj = new Random(0);
    Console.SetCursorPosition(40, 6);
    Console.WriteLine("Your String:");
    Console.WriteLine();       
    for (int j = 0; j < 20; j++)
    { 
       System.Threading.Thread.Sleep(150); Console.SetCursorPosition(53, 6); 
       Console.Write(words[randObj.Next(words.Length - 1)].ToUpper() + "     ");  
    }

    word = words[randObj.Next(words.Length - 1)].ToUpper();
    Console.SetCursorPosition(53, 6);
    Console.Write( word+"    ");
    Console.WriteLine();

    // Create the thread object. This does not start the thread.
    Worker workerObject = new Worker();
    Thread workerThread = new Thread(workerObject.DoWork);

    // Start the worker thread.
    workerThread.Start();

    // Loop until worker thread activates.
    while (!workerThread.IsAlive);

    // Put the main thread to sleep for 1 millisecond to
    // allow the worker thread to do some work:

    Thread.Sleep(3000);
    // Request that the worker thread stop itself:

    workerObject.RequestStop(word);

    // Use the Join method to block the current thread 
    // until the object's thread terminates.

    workerThread.Join();      
}

}

Upvotes: 3

Views: 561

Answers (7)

Arjun
Arjun

Reputation: 1069

I got the solution. The actual problem is with ReadKey(); It doesn't read from the keyboard. Perhaps, it takes the buffer data.

Upvotes: 0

Will Marcouiller
Will Marcouiller

Reputation: 24132

I'll use another probably more appropriate example for threading, through a BackgroundWorker component which is an easy-to-use multi-threading tool. Let's say I have a project with two windows, one is my application, the other is for use as a SplashScreen while the application loads. The BackgroundWorker component is great for such tasks.

using System.ComponentModel.Component;

private BackgroundWorker newThread = new BackgroundWorker();

public void appForm_Load(object sender, EventArgs e) {
    SplashForm sf = new SplashForm();
    sf.Parent = this;

    newThread.DoWork += new EventHandler(newThread_DoWork);
    newThread.RunWorkerAsync(); // Here starts the thread.

    sf.ShowDialog(); // Then shows your splash screen.
}

public void newThread_DoWork(object sender, DoWorkEventArgs e) {
    // TODO: Place the code required by yours tasks here, or call another method to do so.
}

This is a simple example. Assuming this would compile, it will perform your background tasks on a different thread while continuing to show you the splash screen. On this splash screen, you might wish to place a ProgressBar control so that your loading process's progress is reported to your SplashForm through the BackgroundWorker.ProgressChanged() method. You might also wish to Dispose() your SplashForm when the BackgroundWorker is done. This could be done through the BackgroundWorker.RunWorkerCompleted() method.

Following our example, you would have to take your SplashForm declaration outside of your appForm_Load() method so that the BackgroundWorker.RunWorkerCompleted() method may access it to disposal purposes, then your main form shall show.

This is according to me, humbly, the most efficient and easy way to do multi-threading. The BackgroundWorker is very programmer-friendly, without having to care a lot about the locking stuff, delegates, invocations and callbacks.

The .NET Framework 4 shall come with a lot of tools allowing multi-threading done easier: Threadsafe collections, parallel LINQ, etc.

Upvotes: 1

Adrian Cox
Adrian Cox

Reputation: 6334

Does it help to flush the console with Console.Out.Flush()? Your output from the main thread may be waiting in the output buffer while your second thread is already running.

Upvotes: 1

Oliver
Oliver

Reputation: 45071

This is not really a threading problem. It is more a Console problem.

If you press any key within a console, it will be buffered from the Console class and the ReadKey() function just gets the first character in that buffer.

Upvotes: 3

Henk Holterman
Henk Holterman

Reputation: 273169

Your main thread splits of exectly 1 thread and then waits for it to end. There is no purpose to the Thread except that it complicates things.

Threading Lesson #1:

Using Threads is not always an improvement.

Upvotes: 2

Pratik Deoghare
Pratik Deoghare

Reputation: 37172

Also threading DOs and DON'Ts.

Upvotes: 1

Mitch Wheat
Mitch Wheat

Reputation: 300489

Joe Albahari's free ebook on threading is an excellent introduction.

Upvotes: 3

Related Questions