C++ 处理关键应用程序中不应崩溃的异常

C++ 处理关键应用程序中不应崩溃的异常,c++,com,exception-handling,C++,Com,Exception Handling,我有一个正在调试的服务器应用程序,它基本上为请求它的应用程序解析脚本(VBscript、Python、Jscript和SQl) 这是一个非常关键的应用程序,如果它崩溃,会对很多用户造成严重破坏。我面临的问题是如何处理异常,以便应用程序可以继续运行,并且用户知道他们的脚本中是否有错误 例如:在SQL脚本中,应用程序通常返回一组值(日期、数字、字符串和数字)。因此,脚本的结尾必须有这样一个语句: 输入数据日期、数字、数字、字符串。这些是内置到应用程序中的值,服务器应用程序知道如何解释这些值。这些字段

我有一个正在调试的服务器应用程序,它基本上为请求它的应用程序解析脚本(VBscript、Python、Jscript和SQl)

这是一个非常关键的应用程序,如果它崩溃,会对很多用户造成严重破坏。我面临的问题是如何处理异常,以便应用程序可以继续运行,并且用户知道他们的脚本中是否有错误

例如:在SQL脚本中,应用程序通常返回一组值(日期、数字、字符串和数字)。因此,脚本的结尾必须有这样一个语句:

输入数据日期、数字、数字、字符串
。这些是内置到应用程序中的值,服务器应用程序知道如何解释这些值。这些字段在服务器应用程序中被视为数组的一部分。由于数组中这些字段的索引是在服务器应用程序中硬编码的,因此返回值通常应按特定顺序排列

现在,当编写脚本的用户忘记其中一个字段时,最后一个字段(通常为字符串)抛出IndexOutofBoundsException

问题是如何在不关闭应用程序的情况下从这种性质的异常中恢复

另一个示例是脚本中的错误,无法为其生成错误解析消息。这些错误会在应用程序的后台消失,并最终导致服务器应用程序崩溃。它失败的脚本不一定完全无法执行,但它的一部分不执行,而其他部分执行,这使得它在用户看来相当奇怪

此服务器应用程序是本地C++应用程序,使用COM技术。


我想知道是否有人知道最好的方法是如何处理上面描述的异常,而不使应用程序崩溃???

您不能处理有异常的问题。您可以有一个顶级的catch块来捕获异常,并希望不会有太多的程序状态无法恢复,从而试图保持程序的活动状态。仍然不能让用户满意,她等待的查询仍然无法运行


确保更改不会破坏关键业务应用程序的稳定性需要组织。在允许进入生产之前,签署变更并验证其是否按预期工作的人员。QA.

如果您知道某个操作可能引发异常,则需要在此区域添加异常处理

基本上,您需要以异常安全的方式编写代码,通常使用以下准则

  • 处理可能引发异常的临时值
  • 在之后使用临时值提交更改(通常不会引发异常)
如果在处理临时值时引发异常,则不会损坏任何内容,在异常处理中,您可以管理情况并进行恢复


既然您谈到了解析不同的语言,您可能会遇到类似的问题

class IParser //parser interface
{
  virtual bool Parse( File& fileToParse, String& errMessage ) = 0;
};

class VBParser : public Parser
class SQLParser : public Parser
假设Parse()方法引发未处理的异常,则整个应用程序将崩溃。以下是如何在应用程序级别解决此问题的简化示例:

  //somewhere main server code
void ParseFileForClient( File& fileToParse )
{
  try
  {
    String err;
    if( !currentParser->Parse( fileToParse, err ) )
      ReportErrorToUser( err );
    else
      //process parser result
  }
  catch( std::exception& e )
  {
    ReportErrorToUser( FormatExceptionMessage( err ) );
  }
  catch( ... )
  {
    ReportErrorToUser( "parser X threw unknown exception; parsing aborted" );
  }
}

这实际上取决于启动服务器应用程序所需的时间。让应用程序崩溃然后重新加载可能更安全。或者根据Chrome浏览器的提示,在可能崩溃的不同进程中运行应用程序的不同部分。如果您可以安全地恢复异常,并且相信您的应用程序状态正常,那么就可以这样做。但是,捕获std::exception并继续执行可能会有风险

有一些简单到复杂的方法来照看进程,以确保它们在崩溃时可以重新启动。我用了一些工具

蓝丸


pacemaker

适用于由于用户错误而可能在程序内部发生的简单异常, 只需保存可以更改的状态,然后按如下方式恢复:

SaveStateThatCanBeAlteredByScript();
try {
    LoadScript();
} catch(std::exception& e){
    RestoreSavedState();
    ReportErrorToUser(e);
}
FreeSavedState();

如果您想防止外部代码崩溃(可能是不可靠的代码,如插件),则需要IPC方案。在Windows上,我认为您可以使用
OpenFile()
来存储映射文件。在POSIX系统上,如果您有服务器,您可以将
sem_open()
mmap()
一起使用。您基本上有一个主循环,它等待启动作业的信号。信号可能是什么,您的服务器只是浏览文件系统上的文件列表,也可能更像web服务器,它等待连接并执行连接上提供的脚本(或类似的任何东西)

要防止服务器因脚本而崩溃,需要将外部作业封装在受保护的区域中

MainLoop()
{
    // Don't bother to catch exceptions from here.
    // This probably means you have a programming error in the server.
    while(job = jobList.getJob())
    {
        // Catch exception from job.execute()
        // as these exceptions are generally caused by the script.
        try
        {
            job.execute();
        }
        catch(MyServerException const& e)
        {
            // Something went wrong with the server not the script.
            // You need to stop. So let the exception propagate.
            throw;
        }
        catch(std::exception const& e)
        {
            log(job, e.what());
        }
        catch(...)
        {
            log(job, "Unknown exception!");
        }
    }
}

如果服务器对您的操作至关重要,那么仅仅检测问题并将其记录下来并不总是足够的。写得不好的服务器将崩溃,因此您希望自动恢复。因此,您应该编写某种形式的心跳进程,定期检查进程是否崩溃以及是否自动重新启动。

在您的示例中,如何防止可能的损坏状态?没有。。这只是一个简单的例子,它允许Parse方法抛出一个期望,它不会使解析器处于损坏状态。这些链接中的应用非常有趣,但是它们是用于基于*nix的机器的。我的服务器在Windows机器上运行!如果您知道任何可以在win机器上可靠执行相同操作的信息,请告诉我?
MainLoop()
{
    // Don't bother to catch exceptions from here.
    // This probably means you have a programming error in the server.
    while(job = jobList.getJob())
    {
        // Catch exception from job.execute()
        // as these exceptions are generally caused by the script.
        try
        {
            job.execute();
        }
        catch(MyServerException const& e)
        {
            // Something went wrong with the server not the script.
            // You need to stop. So let the exception propagate.
            throw;
        }
        catch(std::exception const& e)
        {
            log(job, e.what());
        }
        catch(...)
        {
            log(job, "Unknown exception!");
        }
    }
}