MultithreadedConsole is a solution that can help a programmer to easily implement a multithreaded UI in a Windows Console Application.
Recently, I was working on a multithreaded implementation that needed some very simple user input. I decided that a Windows Console application would be sufficient for this.
As time went by, and the project grew I wanted to show the user some feedback about the inner happenings of the application. I created some events, and used
Console.WriteLine to show the data.
This worked fine until the user decided to input a command in the console. As you have probably already guessed, this doesn't work very well when multithreading. The user input get complimented with the text printed on the second thread, after which a new line empty line is started:
After some more Googling, I didn’t find any simple to use solution for this problem and I decided to write my own. I want to share my solution with the community.
To me, the best solution seemed to prepend the text from the other thread before the user line. This requires storing user input, then overwriting that input when another thread is writing, and restoring the user input on the next line.
This might sound simple enough, but having some experience writing this article, I knew it was not. The problem lies with intercepting user input. While this is possible using
Console.ReadKey, it also disables features like scrolling through previous commands with the arrow keys. The before mentioned article tackles this problem, so I could reuse it in this solution.
Using the code
The library (attached) provides its own
ConsoleExt.WriteLine method which is very similar to the
Console.WriteLine method .NET provides. The difference is that the new method actually intercepts all input from the user, stores it, and then writes the line. This provides possibility to use the inputted information to, in this case, write it on a new line after the initial input gets overwritten.
The method that should be used by the information threads is called
ConsoleExt.PrependLine. This method prepends a line before the user-input line of the console.
Let's move on to an example:
private static bool _running = true;
static void Main(string args)
Thread eventThread = new Thread(ThreadMethod);
var line = ConsoleExt.ReadLine();
static void ThreadMethod()
for (int i = 0; i < 40; i++)
ConsoleExt.PrependLine("This is an event on a different thread!");
This example simulates an event on a different thread every 4 seconds. Instead of using the
PrependLine is used. The result will be as seen below:
There you have it. A solution that is easy to use, but saves a lot of frustration. For both the programmer and the user.
Points of Interest
The solution is thread safe. Multiple threads can call
When I was looking for solutions to this problem, I did find that other people encountered the same problem. This were mainly cases of implementing a console chat application. This solution could be used for such a case as well.
Of course it is also quite easy to use
Console.CursorTop to overwrite a line in case of loading something in a different thread. However, the goal of this article is demonstrating an easy and reusable way of using a console application with multiple threads. (Think about the chat example).
I haven’t implemented all default console functionality. If you have any good additions, feel free to message me, and I might add them to the project.
ConsoleExt supports more useful console methods. This article has more details about these.
Little disclaimer for the purists: Even though I am all about writing clean code, the
ConsoleExt class contains a huge
switch statement. After many sleepless nights, I deliberately left it this way. In my opinion, splitting it up into smaller parts would actually reduce the readability of the code.
03-05-2017 - Version 1
19-08-2017 - Version 1.1
ConsoleExt to allow for a lot more unit testing and implemented those unit tests.
Enthusiastic Senior Software Engineer.
Experience working in a multinational and multidisciplinary environment with involvement in all stages of the software development process. Supportive and reliable team player with a strong aim towards software quality and customer satisfaction. Fast and eager learner.
His passion for programming can be traced back to his pre-professional days. Where, even as an elementary school student he could be found on the computer creating computer games. The reason? There is just no feeling like being able to think something up, create it, and then see others enjoy it.
Outside the office, he's a contributor to the Code Project and there is always a project he's working on. When he's not coding he likes to make and edit video’s, can discuss theoretical physics for hours and if you challenge him to a board game, he won’t say no. He can also frequently be found in the gym and travels when he can.