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