Link to home
Start Free TrialLog in
Avatar of freefrag
freefrag

asked on

Multithreaded console

Hey!

I want to create a simple multithreaded application in the console
that will display some data while reading data from the user
However I have ran into some trouble.

If one of my threads calls Console.Writeline(), both what the user has typed in and what my program typed in will be displayed at once.

is there any way to store what the user has typed in, display the message
then restore it back to the console?
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Can you post your code?  Sounds like you either need some thread synchronization, or are echoing characters back to the console in addition to .Net also echoing the typed characters.
Avatar of freefrag
freefrag

ASKER

static void Main(string[] args)
        {
            TextWriter txt = null;
           
            Thread Spam = new Thread(new ThreadStart(SPPPPPAM));
            Thread Read = new Thread(new ThreadStart(READDDD));
            Read.Start();
            Spam.Start();
           
        }
        static void READDDD()
        {
            while (true)
            {
               
                string s = string.Format("rrright, so thats what you ment: {0}", Console.ReadLine());
                Console.WriteLine(s);
            }
        }
        static void SPPPPPAM()
        {
            while (true)
            {
                Console.WriteLine("Spammin");
                Thread.Sleep(1000);
            }
           
        }
HI,

Try using Lock like below,

static void READDDD()
        {
            private System.Object lockThis = new System.Object();

            while (true)
            {
               Lock(lockThis)
               {
string s = string.Format("rrright, so thats what you ment: {0}",  Console.ReadLine());
                Console.WriteLine(s);
                }
            }
        }
refer this msdn link
http://msdn.microsoft.com/en-us/library/ms173179%28VS.80%29.aspx
Regards
Deepu
doesnt work probably because the console buffer is a shared resource
I believe both threads need to refer to the same object in order for locking to work, so something like this (sorry, not exactly sure how you intended this to run, or what you're trying to accomplish, but this does demonstrate thread sync using a lock):


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication2
{
	class Program
	{
		static Object lckObj = new Object();
 
		static void Main(string[] args)
		{
			
 
			Thread Spam = new Thread(new ThreadStart(SPPPPPAM));
			Thread Read = new Thread(new ThreadStart(READDDD));
			Read.Start();
			Spam.Start();
 
		}
		static void READDDD()
		{
			
 
			while (true)
			{
				lock (lckObj)
				{
					Console.Write("Enter some text: ");
					string s =  Console.ReadLine();
					Console.WriteLine("You entered {0}", s);
				}
			}
		}
		static void SPPPPPAM()
		{
			while (true)
			{
				lock (lckObj)
				{
					Console.WriteLine("Spammin");
				}
				Thread.Sleep(1000);
			}
 
		}
	}
}

Open in new window

nope, still isnt working.

Now it doesnt type the text until the user presses enter
Well, like I said I'm not sure how you intended for this to run.  The code in your question is kinda like two different programs both running simultaneously on the same console with complete disregard for each other, i.e. if the 1,000ms Sleep() in thread 2 happens to expire while the user is entering text into thread 1's ReadLine() it's not gonna know, or care, and will happily insert "spammin" into whatever the user is typing.

My example uses the lock, so that 1 thread waits for the other, before thread 1 attempts to read anything from the user it locks lckObj, which causes thread 2 to wait until the lock is released - which happens after Console.ReadLine(), i.e. when the user presses enter - this way thread 2 is not inserting text into the console while thread 1 is trying to have the user enter input.  Because thread 1 has no delay, as soon as a user enters text it's prompting for another line, it has the effect of alternating lines of user text & "spammin."

Put a 5 second delay in the READDD loop.
Add Thread.Sleep(5000) in READDD thread *outside* the lock block.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication2
{
	class Program
	{
		static Object lckObj = new Object();
 
		static void Main(string[] args)
		{
 
 
			Thread Spam = new Thread(new ThreadStart(SPPPPPAM));
			Thread Read = new Thread(new ThreadStart(READDDD));
			Read.Start();
			Spam.Start();
 
		}
		static void READDDD()
		{
 
 
			while (true)
			{
				lock (lckObj)
				{
					Console.Write("Enter some text: ");
					string s = Console.ReadLine();
					Console.WriteLine("You entered {0}", s);
				}
				Thread.Sleep(5000);
			}
		}
		static void SPPPPPAM()
		{
			while (true)
			{
				lock (lckObj)
				{
					Console.WriteLine("Spammin");
				}
				Thread.Sleep(1000);
			}
 
		}
	}
}

Open in new window

Maybe this is what you wanted.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication3
{
	class Program
	{
		static Object lckObj = new Object();
 
		static void Main(string[] args)
		{
			Thread inputThread = new Thread(InputThreadProc);
			Thread outputThread = new Thread(OutputThreadProc);
 
			inputThread.Start();
			outputThread.Start();
		}
 
		static void InputThreadProc()
		{
			StringBuilder userInput = new StringBuilder();
 
			while (true)
			{
				if (Console.KeyAvailable)
				{
					char inputChar = Console.ReadKey(true).KeyChar;
					if ((inputChar == '\r') || (inputChar == '\n'))
					{
						lock (lckObj)
						{
							Console.WriteLine("User entered: {0}", userInput.ToString());
							userInput.Remove(0, userInput.Length);
						}
					}
					else
						userInput.Append(inputChar);
				}
				else
					Thread.Sleep(125);
			}
		}
 
		static void OutputThreadProc()
		{
			string outputText = "Hello World";
 
			while (true)
			{
				lock (lckObj)
				{
					Console.WriteLine(outputText);
				}
				Thread.Sleep(1000);
			}
		}
	}
}

Open in new window

still not working.

it stops to let you type in the text, and this is no what I want it to do.

I want the whole program to continute Writing to the console, but allowing the user to input text at the same time. so for example the current output is

Spam
Spam
Spam
Spam
asd

where asd is what the user typed in.
If at the same time the other thread writes a line this is what will happen

Spam
Spam
Spam
Spam
asdSpam

and what I want it to do is

Spam
Spam
Spam
Spam
Spam
asd

so that it adds a line and doesnt delete what the user typed in
In my most recent snippet, on line 30, change true to false.  This will cause the users keystrokes to be displayed on-screen admidst all the "Spammin's", and once the user presses the Enter key, a clean line is output.
Can you Just try a Console.Clear() just after the Second Thread.

Sorry I mean Console.Out.Flush()
This is the type of output you're expecting?  Note that the bold characters are what I typed, and notice how - since both threads are using the console simultaneously - "Hello World" occurs in the middle of whatever I was typing, until I press enter then thread 1 causes thread 2 to pause, outputs whatever I entered, then lets thread 2 resume.

Hello World
ThHello World
e quickHello World
brownHello World
fox juHello World
mped oveHello World
r the laHello World
zy dogHello World
User entered: The quick brown fox jumped over the lazy dog.
Hello World
Hello World
no this is what I was expecting

h

//new line

HelloWorld
hey

//new line

HelloWorld
HelloWorld
 hey there

//new line

HelloWorld
HelloWorld
HelloWorld
 hey there!

//user pressed enter


HelloWorld
HelloWorld
HelloWorld
 You typed in: hey there!
Hmm, this code seems a little overly complex to me, but I think it does what you want. ;)

Hello World
Hello World
Th
Hello World
The
Hello World
Hello World
The quick
Hello World
The quick brow
Hello World
The quick brown
Hello World
Hello World
Hello World
The quick brown fox ju
Hello World
The quick brown fox jumped ov
Hello World
The quick brown fox jumped over the la
Hello World
The quick brown fox jumped over the lazy do
Hello World
User entered: The quick brown fox jumped over the lazy dog.
Hello World
Hello World
Some
Hello World
Something
Hello World
Something else
Hello World
Something else.
Hello World
User entered: Something else.
Hello World
Hello World
Hello World
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication3
{
	class Program
	{
		static Object consoleOutputLock = new Object();
		static Object boolLock = new Object();
		static Object stringLock = new Object();
 
		static bool newKeysEntered = false;
		static StringBuilder userInput = new StringBuilder();
 
		static void Main(string[] args)
		{
			Thread inputThread = new Thread(InputThreadProc);
			Thread outputThread = new Thread(OutputThreadProc);
 
			inputThread.Start();
			outputThread.Start();
		}
 
		static void InputThreadProc()
		{
 
			while (true)
			{
				if (Console.KeyAvailable)
				{
					char inputChar = Console.ReadKey(true).KeyChar;
					if ((inputChar == '\r') || (inputChar == '\n'))
					{
						lock (boolLock) { newKeysEntered = false; }
						lock (consoleOutputLock)
						{
							lock (stringLock)
							{
								Console.WriteLine("User entered: {0}", userInput.ToString());
								userInput.Remove(0, userInput.Length);
							}
						}
					}
					else
					{
						lock (boolLock) { newKeysEntered = true; }
						lock (stringLock) { userInput.Append(inputChar); }
					}
				}
			}
		}
 
		static void OutputThreadProc()
		{
			string outputText = "Hello World";
			bool alsoOutputUserText = false;
 
			while (true)
			{
				lock (boolLock) { alsoOutputUserText = newKeysEntered; }
				lock (consoleOutputLock)
				{
					if (alsoOutputUserText)
					{
						lock (boolLock) { newKeysEntered = false; }
						lock (stringLock) { Console.WriteLine(userInput.ToString()); }
					}
					Console.WriteLine(outputText);
				}
				Thread.Sleep(1000);
			}
		}
	}
}

Open in new window

still not what I mean :/

instead of it displaying

Hello World
Some
Hello World
Something
Hello World
Something else
Hello World
Something else.
Hello World
User entered: Something else.
Hello World
Hello World
Hello World

I dont want to show what the user entered previously.

I just want the input to always be on the bottom of the console, regardless of how many lines the user entered.

Think of it as an internet messenger.
Maybe there is a way, to see and edit what the user types before he presses enter?
ASKER CERTIFIED SOLUTION
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
well this isnt exactly what I wanted, but fair enough. You've done waaaay too much work for this to go unnoticed. You helped me realise what question I need to ask :)

thanks a lot