C#
Console.ReadLine
interrupt
input handling
programming tips

How to interrupt Console.ReadLine

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Console.ReadLine() is a blocking call — it halts execution until the user presses Enter. There is no built-in way to cancel it with a timeout or cancellation token. To interrupt it, you need to run the read on a separate thread and either send a simulated Enter keypress, use Console.KeyAvailable in a polling loop, or replace ReadLine with an async pattern using Console.In.ReadLineAsync(). Each approach has trade-offs in complexity and reliability.

The Problem

csharp
// This blocks forever if the user never presses Enter
string input = Console.ReadLine();

There is no Console.ReadLine(TimeSpan timeout) or Console.ReadLine(CancellationToken) in the .NET API.

Approach 1: Background Thread with Timeout

Run ReadLine on a background thread and wait with a timeout:

csharp
1static string ReadLineWithTimeout(TimeSpan timeout)
2{
3    string result = null;
4    var thread = new Thread(() => result = Console.ReadLine())
5    {
6        IsBackground = true  // Dies when main thread exits
7    };
8    thread.Start();
9
10    if (thread.Join(timeout))
11        return result;     // User typed something
12    else
13        return null;       // Timeout — thread is still blocked on ReadLine
14}
15
16// Usage
17string input = ReadLineWithTimeout(TimeSpan.FromSeconds(10));
18if (input == null)
19    Console.WriteLine("Timed out waiting for input");
20else
21    Console.WriteLine($"You entered: {input}");

The background thread remains alive (blocked on ReadLine) even after the timeout. It terminates when the application exits because it is a background thread.

Approach 2: Console.KeyAvailable Polling

Use a loop that checks for available keystrokes without blocking:

csharp
1static string ReadLineWithTimeout(int timeoutMs)
2{
3    var sb = new StringBuilder();
4    var stopwatch = Stopwatch.StartNew();
5
6    while (stopwatch.ElapsedMilliseconds < timeoutMs)
7    {
8        if (Console.KeyAvailable)
9        {
10            var key = Console.ReadKey(intercept: true);
11            if (key.Key == ConsoleKey.Enter)
12            {
13                Console.WriteLine();
14                return sb.ToString();
15            }
16            else if (key.Key == ConsoleKey.Backspace && sb.Length > 0)
17            {
18                sb.Remove(sb.Length - 1, 1);
19                Console.Write("\b \b");
20            }
21            else if (!char.IsControl(key.KeyChar))
22            {
23                sb.Append(key.KeyChar);
24                Console.Write(key.KeyChar);
25            }
26        }
27        else
28        {
29            Thread.Sleep(50);  // Avoid busy-waiting
30        }
31    }
32
33    return null;  // Timeout
34}

This approach gives full control over the input process and supports cancellation cleanly. The trade-off is that you must manually handle backspace, special keys, and echo.

Approach 3: Task-Based with CancellationToken

csharp
1static async Task<string> ReadLineAsync(CancellationToken ct)
2{
3    var readTask = Task.Run(() => Console.ReadLine());
4
5    var completedTask = await Task.WhenAny(readTask, Task.Delay(-1, ct));
6
7    if (completedTask == readTask)
8        return await readTask;
9
10    // Cancellation was requested
11    return null;
12}
13
14// Usage
15using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
16try
17{
18    string input = await ReadLineAsync(cts.Token);
19    Console.WriteLine(input ?? "Cancelled");
20}
21catch (OperationCanceledException)
22{
23    Console.WriteLine("Timed out");
24}

This integrates with async/await and cancellation tokens. The ReadLine thread still blocks in the background, but the calling code continues.

Approach 4: Console.In.ReadLineAsync() (.NET 7+)

Starting in .NET 7, Console.In.ReadLineAsync() supports CancellationToken:

csharp
1using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
2try
3{
4    string input = await Console.In.ReadLineAsync(cts.Token);
5    Console.WriteLine($"You entered: {input}");
6}
7catch (OperationCanceledException)
8{
9    Console.WriteLine("Input cancelled");
10}

This is the cleanest approach but requires .NET 7 or later. On older runtimes, ReadLineAsync ignores the cancellation token.

Approach 5: Sending a Simulated Enter Key

Force ReadLine to unblock by sending Enter to the console input buffer:

csharp
1using System.Runtime.InteropServices;
2
3// Windows only
4[DllImport("kernel32.dll")]
5static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
6
7// Or use SendKeys (Windows Forms)
8// System.Windows.Forms.SendKeys.SendWait("{ENTER}");

This is platform-specific and fragile. Use it only as a last resort.

Comparison

ApproachTimeoutCancellationClean Unblock.NET Version
Background thread + JoinYesNoNo (thread lingers)All
KeyAvailable pollingYesYesYesAll
Task + CancellationTokenYesYesNo (thread lingers)4.5+
Console.In.ReadLineAsyncYesYesYes7+

Common Pitfalls

  • Lingering background threads: Approaches 1 and 3 leave a thread blocked on ReadLine after timeout. If you call these repeatedly, threads accumulate. The IsBackground = true flag ensures they die when the process exits, but they waste resources until then.
  • Busy-waiting in polling loops: Polling Console.KeyAvailable without Thread.Sleep consumes 100% CPU on one core. Always add a short sleep (20-50ms) in the loop.
  • Assuming ReadLineAsync is truly async on older .NET: Before .NET 7, Console.In.ReadLineAsync() internally blocks a thread pool thread. It does not support cancellation tokens. Check your runtime version.
  • Not handling special keys in the polling approach: If you implement KeyAvailable polling, you must handle backspace, delete, arrow keys, and other control characters manually, or the input experience is broken.
  • Using Console.ReadLine in a GUI application: Console.ReadLine in a Windows Forms or WPF app may not have a console attached, causing IOException. Use a text box or input dialog instead.

Summary

  • Console.ReadLine() has no built-in timeout or cancellation support
  • For .NET 7+, use Console.In.ReadLineAsync(CancellationToken) — the cleanest solution
  • For older .NET, use Console.KeyAvailable polling for clean cancellation or a background thread with Thread.Join(timeout)
  • Background thread approaches leave a blocked thread after timeout — use IsBackground = true so it does not prevent process exit
  • Always add Thread.Sleep in polling loops to avoid CPU waste

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.