我有一个控制台应用程序,我想给用户x秒的时间来响应提示.如果在一段时间后没有输入,程序逻辑应该继续.我们假设超时意味着空响应.

解决这一问题最直接的方法是什么?

推荐答案

我惊讶地发现,5年后,所有的答案仍然存在以下一个或多个问题:

  • 使用了ReadLine以外的函数,导致功能丢失.(先前输入的DELETE/BACKSPACE/UP-键).
  • 函数在多次调用时表现不佳(产生多个线程、许多挂起的ReadLine或其他意外行为).
  • 函数依赖于忙等待.这是一种可怕的浪费,因为预计等待时间从几秒到超时(可能是几分钟).运行这么长时间的忙碌等待是对资源的可怕吸收,这在多线程场景中尤其糟糕.如果用睡眠来改变忙碌等待时间,这会对响应性产生负面影响,尽管我承认这可能不是什么大问题.

我相信我的解决方案将解决最初的问题,而不会出现上述任何问题:

class Reader {
  private static Thread inputThread;
  private static AutoResetEvent getInput, gotInput;
  private static string input;

  static Reader() {
    getInput = new AutoResetEvent(false);
    gotInput = new AutoResetEvent(false);
    inputThread = new Thread(reader);
    inputThread.IsBackground = true;
    inputThread.Start();
  }

  private static void reader() {
    while (true) {
      getInput.WaitOne();
      input = Console.ReadLine();
      gotInput.Set();
    }
  }

  // omit the parameter to read a line without a timeout
  public static string ReadLine(int timeOutMillisecs = Timeout.Infinite) {
    getInput.Set();
    bool success = gotInput.WaitOne(timeOutMillisecs);
    if (success)
      return input;
    else
      throw new TimeoutException("User did not provide input within the timelimit.");
  }
}

当然,打电话很容易:

try {
  Console.WriteLine("Please enter your name within the next 5 seconds.");
  string name = Reader.ReadLine(5000);
  Console.WriteLine("Hello, {0}!", name);
} catch (TimeoutException) {
  Console.WriteLine("Sorry, you waited too long.");
}

或者,您可以使用TryXX(out)公约,正如shmueli所建议的:

  public static bool TryReadLine(out string line, int timeOutMillisecs = Timeout.Infinite) {
    getInput.Set();
    bool success = gotInput.WaitOne(timeOutMillisecs);
    if (success)
      line = input;
    else
      line = null;
    return success;
  }

其名称如下:

Console.WriteLine("Please enter your name within the next 5 seconds.");
string name;
bool success = Reader.TryReadLine(out name, 5000);
if (!success)
  Console.WriteLine("Sorry, you waited too long.");
else
  Console.WriteLine("Hello, {0}!", name);

在这两种情况下,您不能将拨打Reader的电话与正常拨打Console.ReadLine的电话混在一起:如果Reader超时,将有一个挂起的ReadLine电话.相反,如果你想有一个正常的(非定时)ReadLine调用,只需使用Reader并省略超时,这样它就默认为无限超时.

那么我提到的其他解决方案的问题呢?

  • 如您所见,使用了ReadLine,避免了第一个问题.
  • 该函数在多次调用时运行正常.无论是否发生超时,只有一个后台线程在运行,并且至多只有一个对ReadLine的调用处于活动状态.调用该函数将始终导致最新的输入,或者导致超时,并且用户不必多次按Enter键即可提交其输入.
  • 显然,该功能不依赖于繁忙的等待.相反,它使用适当的多线程技术来防止浪费资源.

我预见到这个解决方案的唯一问题是它不是线程安全的.然而,多个线程不能同时请求用户输入,所以在调用Reader.ReadLine之前应该先进行同步.

.net相关问答推荐

从Couchbase删除_txn文档的推荐方法?""

PowerShell中窗体定时器和系统定时器的统一处理

AutoMapper在实体框架查询后不知从哪里带来数据

.NET 7.0中的UseHttpsRedirection和IIS生产部署

在数据网格中:如何在更改单元格 A 中的值后显示单元格 B 中的更改

部署时如何控制红隼端口?

Owin Twitter登录-根据验证程序远程证书无效

如何将浮点数向上舍入到 C# 中最近的 int?

IEnumerable Count() 和 Length 的区别

如何在 .NET 中将字符串转换为字节数组?

是否有用于 Windows / C# 开发的可嵌入 Webkit 组件?

如何使用 C# 创建自签名证书?

.NET Framework SDK 和 Targeting 包有什么区别

为什么会出现编译错误使用未分配的局部变量?

如何使用 Entity Framework Code First CTP 5 存储图像?

C# 中的 F# List.map 类似功能?

如何从其十六进制 RGB 字符串创建 System.Drawing.Color?

带有嵌套控件的设计模式

如何将 VB 项目转换为 C# 项目

浮动与双重性能