4

特定のマシンで 24 時間年中無休で実行されるライブラリがあるとします。コードがしっかりしていても、遅かれ早かれハードウェア障害によって例外が発生する可能性があります。このようなイベントに備えて、何らかのフェールセーフを配置したいと考えています。1 つのアプローチは、各 API をカプセル化するラッパー関数を作成することです。

returnCode=DEFAULT;
try
{
  returnCode=libraryAPI1();
 }
catch(...)
{
 returnCode=BAD;
}
return returnCode;

次に、ライブラリの呼び出し元がスレッド全体を再起動し、returnCode が正しくない場合はモジュールを再初期化します。

物事はひどくうまくいかない可能性があります。例えば

try ブロック (または libraryAPI1()) が次の場合:

 func1();
 char *x=malloc(1000);
 func2();

func2() が例外をスローすると、x は決して解放されません。同様に、ファイルの破損も考えられる結果です。

このシナリオで他に何が問題になる可能性があるか教えてください。

4

4 に答える 4

4

このコード:

func1();
char *x=malloc(1000);
func2();

C++ コードではありません。これは、人々がクラス付き C と呼んでいるものです。これは、C++ のように見えますが、実際の C++ の使用方法と一致しないプログラム スタイルです。その理由は; 優れた例外セーフ C++ コードでは、コード内でポインターを (直接) 使用する必要は実質的にありません。ポインターは、例外セーフ マナー (通常はスマート ポインターまたはコンテナー) で寿命を管理するように特別に設計されたクラス内に常に含まれているためです。

そのコードに相当する C++ は次のとおりです。

func1();
std::vector<char> x(1000);
func2();
于 2010-05-20T16:38:41.433 に答える
3

ハードウェア障害によって C++ 例外が発生することはありません。一部のシステムでは、ハードウェア例外は C++ 例外とはまったく異なるメカニズムです。その他では、C++ 例外はハードウェア例外メカニズムの上に構築されます。したがって、これは実際には一般的な設計上の問題ではありません。

回復できるようにしたい場合は、トランザクショナルである必要があります。各状態変更は、完了するまで実行するか、完全にバックアウトする必要があります。RAII はその一部です。Chris Becke が別の回答で指摘しているように、リソースの取得以外にも述べるべきことがあります。

copy-modify-swap というイディオムがあり、これはトランザクションによく使われますが、この 100 万分の 1 のケースを処理するために作業コードを適応させようとしている場合、それは重すぎるかもしれません。

本当に堅牢性が必要な場合は、コードをプロセスに分離します。ハードウェア障害によってプロセスが強制終了された場合は、ウォッチドッグでプロセスを再起動できます。OS は、失われたリソースを再利用します。あなたのコードは、ファイルに保存されたものなど、永続的な状態のトランザクションであることだけを気にする必要があります。

于 2010-05-20T17:09:54.997 に答える
2

例外の問題は、RAiI でリエンジニアリングを行ったとして、非同期になるコードを簡単に作成できることです。

void SomeClass::SomeMethod()
{
  this->stateA++;
  SomeOtherMethod();
  this->stateB++;
}

この例は人工的に見えるかもしれませんが、何らかの方法でクラスの状態を変更する操作を stateA++ と stateB++ に置き換えると、このクラスの期待される結果は、状態が同期したままになることです。RAII は、例外を使用する場合の状態に関連する問題の一部を解決する可能性がありますが、それが行うのは誤った安心感を提供することだけです。 SomeOtherMethod() がすべての例外をスローする場合、周囲のコードを分析して事後条件 (stateA. delta == stateB.delta) が満たされます。

于 2010-05-20T08:06:03.033 に答える
2

libraryAPI の実装を制御できますか?

OO モデルに適合する場合は、RAII パターンを使用して設計する必要があります。これにより、デストラクタ (取得したリソースを解放する人) が例外で呼び出されることが保証されます。

スマートポインターなどのリソース管理ヘルパーの使用も役立ちます

try
{
    someNormalFunction();
    cSmartPtr<BYTE> pBuf = malloc(1000);
    someExceptionThrowingFunction();    
}
catch(...)
{
    // Do logging and other necessary actions
    // but no cleaning required for <pBuf>
}
于 2010-05-20T03:37:46.397 に答える