我在一家小公司工作,开发具有丰富UI的复杂医疗设备。我们目前处于设计的早期阶段。该应用程序针对Windows(仅限桌面),最好只能用C ++编写。
经过一些研究后,我们倾向于选择Qt来开发UI。它似乎满足了我们所有的需求,即可以开发具有现代外观和高响应性的UI,开发速度相当快(熟悉后),内存使用在某种程度上是合理的,免费用于商业用途(对我们来说是奖励)。
我的问题是:它对于医疗设备是否足够可靠?我们绝对不能接受考试中的任何崩溃。我知道首先它当然取决于我们编写的代码质量,但我仍然想知道是否有人遇到任何特别难以解决的与崩溃相关的神秘问题。特别是当使用作为脚本语言的QML时,它自然会导致难以预测和解释的错误。
在生产中遇到这样一个问题的成本对我们来说非常高,所以在我们选择任何特定的包之前,我们非常需要做出正确的决定。如果您知道在我们的特定环境中可能出现的任何其他与Qt相关的问题(我承认无法进行非常广泛的包测试),我也非常感谢您提及它。
在我看来,如果你遵循他们的编码风格,Qt足够稳定。我还会购买Digia的支持并使用该库的稳定版本。
事情归结为:
- 评估使用Qt(或任何其他GUI库)引入的风险
- 针对这些风险采取防御措施(引入涵盖风险的新要求和测试,例如将GUI作为通过TCP或其他方式与核心通信的单独进程运行)
- 评估应用程序崩溃的风险,并记录该方案发生时要遵循的过程。
根据我对医疗设备认证的经验,设备的大声崩溃优于静音和错误的操作设备。
如有疑问,请询问正在关注您的案件的认证机构。
另外,看看标准(例如60601-1-4或现在使用的任何标准)。
Qt在医疗应用中的用法: http://qt.nokia.com/qt-in-use/qt-in-medical/
我会认为高可靠性工程的基本原则是充分的。有了这些,你可以使用Qt。现在,Ambroz Bizjak提到了一些“麻烦”的情景。当你遵循基本规则时,它们是无关紧要的。
那么,这些规则是什么?他们不是很难。确定可能失败的位,并在故障不严重时执行这些操作。例如,Ambroz对窗口删除有一个很好的观点。不要在考试中这样做。将对象转储到延迟删除队列中,并确保它们不会干扰操作(即对象必须具有被动状态。例如,对于小部件,包括不可见)。同样,在开始检查之前,创建您可能需要的所有对象(包括所有可能的对话框窗口)。
你可以很好地总结一下这个
- 可能失败的准备工作
- 事情可能不会失败
- 可能失败的清理
由于已经提到的原因,我会避免使用QML。上面的计划突出了它为何如此成问题。您无法将所有可疑的QML步骤移至准备阶段。
我假设您没有开发安全关键设备,因为您运行Windows并且Windows许可协议有一些关于此的说法。所以你的问题确实是, “我们正在制造一种必须尽可能稳定的消费产品,否则我们会看起来非常非常糟糕”。
就个人而言,我可以建议使用C#,因为它在Windows下具有出色的工具,并且开发起来更加容易和安全(垃圾收集器是您的稳定性的朋友,如果不是性能),并且单元测试稍微更方便。对任何性能关键部分使用C ++或C ++ / CLR,但没有理由使用这种复杂且具有潜在危险的语言来构建GUI。
从我对Qt的经验来看,当可靠性很重要时,这是一个糟糕的选择。例如,许多崩溃是由看似有效的代码引起的,但是在某些特定的上下文中做了某些事情,Qt的某些部分没有预料到。在这里,我列出了Qt在编写正确代码时遇到的一些问题:
删除QObjects(读取:任何东西)是一个非常痛苦的过程。如果你从这个对象发出的信号中删除它(读取:一半的时间),你的程序可能会崩溃,因为发出信号的代码不会在你发出处理程序返回信号后检查对象是否仍然存在。继续使用它。
如果仔细观察,建议的解决方法是使用QObject :: deleteLater(),这将使事件循环删除对象 有时候,它是安全的。虽然这看起来似乎可以接受,但考虑到那段时间内的对象 仍然存在并且可以发出信号。这会引入不必要的中间状态,您必须处理这些状态 将 介绍错误;很可能在非常特殊的情况下很少发生(读:不是在你测试的时候)。无论如何, 这一页 讨论了QObject删除的一些问题。
Qt中的其他类具有类似的删除相关问题。例如,如果在其mousePressEvent处理程序中从其场景中删除项目(而不是删除它),QGraphicsScene :: removeItem()可能会导致崩溃。这似乎没有在任何地方记录。
Qt课程充满了 便利功能 与核心功能组合在一起,很难弄清楚课程的实际运作方式以及如何正确使用它。例如,除了stateChanged()信号旁边的QProcess,它是唯一需要的信号,它有像error(),finished()和started()这样的信号,它们的语义和正确的处理并不完全清楚。
许多抽象接口设计糟糕且定义不明确。例如,类QIODevice用于 阅读和写作 和 阻塞和异步I / O.。一个类可以自由选择要实现的子集。这违反了抽象接口的整个概念,即实现接口的任何东西都以定义和一致的方式工作。
没有 真的很好,很均匀 处理事件的方式。有两种 事件 在Qt: QEvents,通过重新实现虚函数来安装回调,以及 信号。 为什么? 无论如何,这两种事件最终只是调用函数(直接在这里忘记排队信号)。这意味着各种模块只能通过调用彼此的功能进行通信。如已经看到的那样,这是有问题的,因为当模块调用另一个模块时,其他模块可能真的已经完成了 什么并且可能很难在每个回调站点考虑所有可能的场景(正如我们所见,Qt没有,而是崩溃)。
通过向事件循环添加功能可以完全解决此问题,这允许跨模块更容易地进行通信和同步。我在描述这个设计 这个问题。
总而言之,当你瞄准最大可靠性时 不要 您基于程序的框架中的此类设计问题 不要 几乎每一步都要解决它的问题。即使你正确地解决了你能想到的所有问题, 你怎么知道没有更多?我想你应该尝试在Qt中编写一些完全正确的代码(也就是说,阅读所有文档,并且 思考每一步 你正在做什么以及框架将如何反应)。过了一段时间,问问自己:你呢? 相信 框架,还是你觉得它试图欺骗你?