2011-06-24 7 views
0

私は、整数のID値を保持するファイルを持っています。問題がGetId()後に後続のアクションが失敗するかもしれないということです1つのスレッドだけがリソースから読み取ることを許可するロックを作成するにはどうすればよいですか?

public int GetId() 
    { 
     _fileLock.EnterUpgradeableReadLock(); 
     int id = 0; 
     try { 
      if(!File.Exists(_filePath)) 
       CreateIdentityFile(); 

      FileStream readStream = new FileStream(_filePath, FileMode.Open, FileAccess.Read); 
      StreamReader sr = new StreamReader(readStream); 
      string line = sr.ReadLine(); 
      sr.Close(); 
      readStream.Close(); 
      id = int.Parse(line); 
      return int.Parse(line); 
     } 
     finally { 
      SaveNextId(id);  // increment the id 
      _fileLock.ExitUpgradeableReadLock(); 
     } 
    } 

:現在のファイルを読むことなどReaderWriterLockSlimで保護されています。あなたが見ることができるように、GetId()メソッドは毎回IDをインクリメントし、IDを発行した後に何が起こるかは無視します。発行されたIDはハングアップする可能性があります(例外が発生する可能性があります)。 IDがインクリメントされると、一部のIDは未使用のままになることがあります。

私はSaveNextId(id)を取り除くことを考えていましたが、それを削除してください(SaveNextId()は実際にはロックを使用しますが、それ以外はEnterWriteLockです)。そして、必要なすべてのメソッドが実行されたら、外部から手動で呼び出します。これにより、SaveNextId()が実行される前に複数のスレッドがGetId()メソッドに入り、すべて同じIDを受け取る可能性があるという別の問題が発生します。

私は操作後にIDを変更する必要はありません。何らかの方法でIDを変更する必要はありません。なぜなら、それはうまくいかず、より多くの問題につながる可能性があるからです。

私は何とかFileIdentityManager(これらのIDを処理するクラス)にコールバックでき、次のIDの保存を実行できることをマネージャに知らせるソリューションが必要です。 ID。

要点リレーショナルデータベースの自動インクリメントの動作を複製したい - 行挿入中に何か問題が生じた場合、そのIDは使用されず、引き続き使用できますが、同じIDが発行されることはありません。うまくいけば、問題は

UPDATE ..あなたは、いくつかのソリューションを提供するための十分な理解:私は私がしたい

+0

私は非連続IDを持つことが悪いことだと思いますか? – Chris

+0

一度に1つのスレッドしか許可しないロックを望むなら、 'lock'を使わないのはなぜですか?私はちょうど質問よりむしろタイトルを読んだ! –

+0

私は削除の結果として起こるものと一緒にします。しかし、私は不成功のファイルセーブ、不成功な型キャストなどでそれらを無駄にしたくありません。私はそれを今働いていますが、この問題は素早く表示され、IDがUIに公開されているので醜いです。 2つの並行コンテンツ項目は、10個以上離れたIDを持つことがあります。 – mare

答えて

2

Essentialyをしたい動作の詳細については答えにコメントを参照してください リレーショナルデータベースの自動インクリメント 行動を複製 - を何行挿入時に うまくいかない場合は、IDは、それはまだAVで、使用されていない です使用できません 同じIDが発行されることもありません。 うまくいけば、 質問が十分に理解できます。 あなたはいくつかの解決策を提供します。

一般的に言えば、私が観察した動作ではありません。トランザクション内にオートインクリメントを含むテーブルに行を挿入し、ロールバックするとIDが失われます。

私の意見では、これを実装した方法は正しい動作です。

アップデートは、あなたがいることを確実にすることができる唯一の方法「unsuccesfulファイルが保存されますでそれらを無駄にしたくないが、unsuccesfulタイプ等、キャスト」 新しいIDを要求してから保存が完了し、増分をIDにロールバックできなくなるまで、ブロッキングコードの範囲をブロックすることです。

これにより、達成できる並列処理のレベルが大幅に低下します。

並列性の可能性を高めたい場合は、IDをリクエストする前にできることをすべて確認する必要があります。タイプをチェックし、エラーをフォーマットします。

外部エラー(IO例外)のようなものは、明らかに何もできません。

+0

これは確かに当てはまりますが(もう一度チェックアウトする必要があります)、私は本当に問題を解決したいと思っています。なぜなら、SQL Serverではそれは... – mare

+0

今、あなたはもう少し良くなっています。 @WraithNathが提案したようにロックを使用することにしましたが、リポジトリでロックを使用することにしました。ロックブロックにはtry..catchブロックが含まれ、tryにはGetId()、追加呼び出し、SaveNextId()が含まれます。 GetId()とSaveNextId()は、ReaderWriterLockSlimを使用して現在の状態のままです。しかし、私は質問があります。これはASP.NET MVCアプリケーションであり、Ninjectを使用してInRequestScope()オプションを使用してリポジトリを作成する方法については、どういう意味がありますか? – mare

2
private static readonly object _lock = new object(); 

    public int GetId() 
    { 
     lock(_lock) 
     { 
     //You code to get ID here 
     } 
    } 
+0

IDを取得するコードがロックを終了したときにimmediatellyロックが解除され、別のスレッドに入ることができると思いますか?私たちは書面に何が起こったのかを知る前にあったでしょうか? – mare

+0

はい、ロックスコープ外でコードが実行されると、コードはロックを解除し、別のスレッドが入ることを許可します。あなたは、あなたの次のIDが何をしようとしているか、そしてそれを元に戻すかどうかを決定するために、ロックの中に入れたいロジックを置くことができます。しかし、このメソッドがアプリケーション全体で使用されている限り、一度に1つのスレッドしか通過できません。 – WraithNath

+0

私のGetId()メソッドは、データアクセスと挿入を扱うリポジトリから呼び出されます。それは、FileIdentityManagerクラスからIDを要求し、XMLにシリアライズされるオブジェクト(ID割り当てを含む)を構築します。シリアライゼーション中に例外が発生した場合は、そのIDをロールバックして発言する必要があります。 – mare

0

ID生成と行挿入がアトミックなため、データベースに表示される動作は可能です。アプリケーションでこの動作をしたい場合は、データを格納する直前にIDを取得することをお勧めします。これにより、「トランザクションスコープ」が最小限のウィンドウに縮小され、例外からの干渉を防ぐことができます。

何か悪い理由でこれができない場合は、IDカウンターをキャッシュする「IDブローカー」を使用することもできます。ファイルから現在のカウンタを読み込み、何らかの数値(たとえば100)をインクリメントした後、連続したIDをシングルスレッド方式ですべての呼び出し元に渡します。 100をすべて渡したら、ファイルを再度更新します。シャットダウン時には、最後に渡された値を使用してファイルを最後に書き出します。唯一の問題は、システムがクラッシュしてIDの隙間を埋める場合ですが、それを補う方法があります。

関連する問題