Caution
请注意,本页面描述的是当前正在进行的工作。
故障类型(非学术性)#
可以区分以下类型的问题:
- 启动输入数据不正确(未设置强制值,或本应为数值时却不是等)
- 动态输入数据不正确
- 我们设计或实现中的某些内容不正确(例如尝试从字符串选项中获取整数、空指针异常、尝试访问已删除的类等)
- 系统故障(内存不足等)
启动输入数据和动态输入数据之间的区别并不像想象的那么容易。基本上,启动指的是直接在命令行或通过配置文件引用的所有内容,而动态则指通过不同接口(如 GUI 或套接字连接)进行的交互式输入。问题是,启动时提供的一些数据会被模拟延迟处理(尤其是路径),并且由于性能问题,在启动时甚至可能无法检查(例如检查格式是否正确的 XML)。这类数据将被视为动态数据。
因此,术语启动输入数据指的是在应用程序开始执行任何有用操作(无论那意味着什么)之前处理的每个数据(文件)。
命令行应用程序#
命令行应用程序的理念#
我们假设所有输入数据都应该是有效的。我们不会尝试解决用户造成的任何错误。我们只是通知他哪里出了问题,并让他修补问题。对于启动数据,这意味着如果遇到错误数据,我们将以错误消息结束应用程序。由于输入数据可能在多个地方损坏,应用程序应首先尝试解析所有数据,报告所有遇到的错误,然后退出。对于动态数据,这意味着,如果我们无法提供直接反馈(例如在单向套接字连接上),我们会忽略该数据(并记录类似日志的消息),否则我们会尝试提供反馈。
编程错误应以允许追踪它们的方式被捕获。用户不应面对任何段错误弹出窗口或类似的东西。相反,应打印关于不当行为的错误消息(当前为:“Quitting (on unknown error).”),并且应用程序应正确退出。
系统错误应被捕获并打印给用户。然后应用程序应正确退出。
命令行应用程序中的实现#
不正确的启动数据#
如#命令行应用程序的理念所述,我们只是报告问题然后退出(附带一条无法完成所需操作的信息)。
为此,我们每个命令行应用程序的主函数都有一个 try/catch 块,该应用程序执行的所有处理都在此块内完成。始终捕获的是在 src/utils/common/UtilExceptions 中定义的 ProcessError 异常。此类包含一条消息,一旦到达主函数中的 try/catch 块,就会报告该消息。由于在 SUMO 的早期版本中,可以调用没有消息的 ProcessError(在这种情况下,消息被设置为“Process Error”),我们仅在捕获的 ProcessError 确实设置了消息时才打印该消息。
int
main(int argc, char **argv)
{
// 初始化返回代码
int ret = 0;
... 进行非关键初始化 ...
try {
... 执行一些关键操作 ...
} catch (ProcessError &e) {
if(string(e.what())!=string("Process Error") && string(e.what())!=string("")) {
MsgHandler::getErrorInstance()->inform(e.what());
}
MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
// 将返回代码设置为“失败”
ret = 1;
#ifndef _DEBUG
} catch (...) {
MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
// 将返回代码设置为“失败”
ret = 1;
#endif
}
... 清理 ...
// 返回返回代码
return ret;
}
第二个 catch 块将在后面描述。
所以基本上,我们要做的唯一事情就是一旦某件事不符合我们的预期,就生成一个 ProcessError 并给它一个适当的消息。然而,这只说对了一半。因为我们不希望应用程序在发生错误时立即退出,而是打印所有错误然后退出,所以我们必须插入一个额外的错误处理层。在当前的实现中,解析输入数据的处理程序将错误报告给 MsgHandler 的错误实例。一旦文件读取结束,就会检查是否发生了错误。如果是这种情况,则会抛出一个 ProcessError。如果处理程序不是自己解析数据,而是使用其他结构,这些结构可能会抛出 InvalidArgument,然后必须捕获该异常并报告给 MsgHandler 的错误实例。
请注意,在抛出 ProcessError 之前,必须删除一些已经分配的内容。
实现错误#
上述代码片段中的第二个 catch 块目前旨在捕获所有其他内容。事实上,这可能是系统故障和编程错误。因此,我们只在发布版本中捕获此异常,以便最终用户被告知错误(尽管没有详细的错误消息)。在我们调试代码的情况下,异常/故障不会被捕获——我们的调试器应停留在生成异常的位置。
系统故障#
目前由后面的 catch 块捕获。可能,处理这些故障的最简单方法是提供一个可能的故障列表,并尝试在 catch 块中处理它们,就像处理 ProcessErrors 那样。
GUI 应用程序#
GUI 应用程序的理念#
对于命令行应用程序来说是致命的(错误的输入参数)对于 GUI 应用程序来说则不是,它应报告错误,但仍应允许用户修补其输入并尝试重新加载设置。
未解决的问题#
SUMO#
- 网络错误
- 没有检查链接一致性;确切地说,某些路口/传入边 <-> 当前边 <-> 后继边的组合可能不匹配,但仍然可以加载而不会出现错误
- 没有检查未使用的值
- WAUT 错误
- 尽管发生了错误,为什么仍会构建 tls-switch 输出?(参见 tests/sumo/errors/wauts/cross3ltl_error_unknown_wautid)
- 程序以一种惰性方式检查,错误报告得太晚(参见 tests/sumo/errors/wauts/cross3ltl_error_unknown_to_prog)
- cross3ltl_error_missing_junctiondef、cross3ltl_error_missing_reftime 的未描述行为
