2

私はこの質問をしましたが、何人かの人々がより多くの情報を求めました。だから私はより多くの情報を提供しています。

私はスマートカードとリーダーを持っています。ユーザーはいつでもリーダーからカードを取り外すことができます。スマート カードにはさまざまなブロック (16 バイト) があり、必要なブロックに書き込むことができます。

これで、スレッドとして実行される次の関数ができました。

3    void function (void *p)
4    {
5        if(smartCardRemoved)
6            doSmth();
7        else
8        {
9            // Smart card is inside the reader
10           writeDataToCard(handle, blockNr, data1);
11            blockNr++; 
12           writeDataToCard(handle, blockNr, data2); 
13           blockNr=12;
14           readDataFromCard(blockNr, credit);
15           credit--;
16           writeDataToCard(cardHandle, blockNr, credit);
        }
    }

data1data2は基本的にタイムスタンプでありcredit、カードのクレジットです。今問題はです。ステップ 10 と 12 が実行されたとします。つまり、タイムスタンプがカードに書き込まれます。しかし今、ユーザーはリーダーからカードを取り外します - これは、ステップ 14、15、16 が実行されないことを意味します - タイムスタンプは書き込まれましたが、クレジットが減少しなかったため、これは私にとって問題です。これは私が言ったように問題です。したがって、ステップ 10 と 12 が実行された場合は、ステップ 14、15、および 16 も実行する必要があります。これに対処する方法は何ですか?

ps。確認する必要がありますが、単一のコミットですべてを書き込むことはできない場合があります。

pps。考えてみると、ステップ 12 が成功した場合、同様の問題が発生する可能性があると思いますが、ステップ 15 で例外がスローされるか、false が返されます。そのような場合はどうすればよいですか?

思慮深く慎重な回答をいただければ幸いです。ありがとうございました。

4

3 に答える 3

1

コミット ジャーナルの使用を検討してください。コミット ジャーナルは、多くのファイル システムやデータベース サーバーで使用されているメカニズムであり、予期しない停電、システム クラッシュ、またはデバイス接続障害が発生した場合でもデータの整合性を確保します。

コミット ジャーナルの基本的な考え方は、実際のブロックにデータを書き込む前に、他のブロックに書き込もうとしている内容を書き留めておくことです。次に、書き込み操作が中断された場合は、コミット ジャーナルを確認して、中断された完全な書き込み操作を再生できます。これにより、データが一貫した状態に戻ります。

カード上のこれに N+1 ブロックを割り当てます。ここで、N は変更するブロックの数です。この場合、5 つのブロックを変更しているように見えるため、ジャーナルには 6 つのブロックが必要です。6 番目のブロックは、実際の書き込みが不完全であったかどうかを示す「状態」です。

たとえば、次のように 6 つのジャーナル ブロックをレイアウトできます。

Journal block: |  0  |  1  |  2  |  3  |  4  |   5   |
Contents:      | B10 | B12 | B15 | B16 | B17 | STATE |

状態ブロックは、「ダーティ」または「クリーン」を示すことができます。これらの状態にどの値を使用するかは重要ではありません。(たとえば、true または false を使用できます。意味が明確になるようJOURNAL_STATE_DIRTYに、 andのようなコンパイル時の定数にすることをお勧めします。)JOURNAL_STATE_CLEAN

カードがフォーマットされると、状態ブロックは「クリーン」に初期化される必要があります。

操作の基本的な順序は次のようになります。

  1. 新しいデータを 5 つのジャーナル ブロックに書き込みます。
  2. ステート ブロックをダーティに設定します。
  3. 新しいデータを実際の宛先ブロック (10、12、15、16、17) に書き込みます。
  4. 状態ブロックを clean に設定します。

カードを初期化するとき、最初に行うことは、状態がダーティかどうかを確認することです。そうである場合は、手順 3 で書き込み操作を再開してジャーナルを再生します。ただし、この場合は、ジャーナル ブロックから「新しいデータ」を読み取っています。

ステップ 2 が完了する前に操作が中断された場合、状態ブロックは「クリーン」である必要があり、ジャーナルの再生は実行されません。書き込みは完全に失敗し、カードには完全に無傷の古いデータが含まれます。

ステップ 2 の完了後に操作が中断された場合、状態ブロックは「ダーティ」になり、次にデバイスが接続されたときにジャーナルが再生されます。実際のブロック 10、12、15、16、および 17 は破損している可能性がありますが、ジャーナルを再生するとこれが修正され、ジャーナルの再生後にブロックが正しい新しい値を持つようになります。

このアプローチは、カードを使用するすべてのソフトウェアがこのジャーナル手法を理解し、実装している場合にのみうまく機能することに注意してください。 ユーザーが書き込み中にカードを取り外して、ジャーナルを認識していないデバイスに持ち込んだ場合、破損したデータが使用されます。これについてあなたができることは何もありません。

過度に偏執的になりたい場合は、5 つのデータ ブロックのチェックサムを含む別のブロックをジャーナル専用にします。これにより、再生ステップ中にジャーナル データが破損しているかどうかを検出できます。その場合、カードが破損しており、修理が必要であることをユーザーに通知できます。

于 2013-09-30T17:59:16.583 に答える
0

循環バッファを実装する必要があります

データ構造にはbool値が含まれるため、一連の命令が完了した後、最後にvalidをtrueに設定してから処理を終了し、function 書き込みごとにバッファを循環して、未完了のアクセスを検出できます

于 2013-09-30T17:43:18.807 に答える