1

読み書きされるファイルがあります。いつ書き込まれたかを確認する必要があります。他の誰もそれに書き込もうとしません。

読み取りまたは書き込みを許可する関数全体をロックしましたが、別のプロセスで使用されているため、プロセスはファイル 'FILENAME' にアクセスできません。

public static TYPE Property{

get{
    data mydata;
    Object obj = new object();
    Monitor.Enter(obj);

    // check if data has not changed
    // if it has not, just read

    using (Stream stream = File.Open(fileLocation, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
        //....
    }
    // else, if data changed, then need to write to  file to save the new data

    using (Stream stream = File.Open(fileLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)) {
        BinaryFormatter bf = new BinaryFormatter();

        try {
            bf.Serialize(stream, (data);
        }
        //DONE processing

        Monitor.Pulse(obj);
        Monitor.Exit(obj);
        return data
}
4

3 に答える 3

10

プロパティが呼び出されるたびにロックする新しいモニターを作成しています。同じモニターをロックする必要があります。そうしないと、ロックしても意味がありません。

また、「ロック」ステートメントを使用する必要があります。待機することはないため、パルスしても意味がありません。現在、例外がスローされると、ロックが「リーク」することになります。これは通常、非常に悪い問題ですが、とにかくロックを再利用していないため、問題が隠されています。

例えば:

private static readonly object monitor = new object();

public static TYPE Property
{
    get
    {
        lock(monitor)
        {
            // check if data has not changed
            // if it has not, just read
            using (Stream stream = File.Open(fileLocation, 
                   FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                ....
            }
            // else, if data changed, then need to write to 
            // file to save the new data
            using (Stream stream = File.Open
                       (fileLocation, FileMode.OpenOrCreate,
                        FileAccess.ReadWrite, FileShare.Read))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(stream, data);
            }
            return data;
        }
    }
}

余談ですが、これは私がプロパティで実際に期待するよりも多くの作業を行っているようです。メソッドがもっと意味をなさないと確信していますか?

于 2009-10-23T18:21:56.747 に答える
4

さて、Monitor.Enter は、同じオブジェクトをロックしようとするスレッドのアクセスをブロックします。ゲッターを入力するたびに新しいオブジェクトが作成されるため、すべての呼び出し元は互いに何も知らない新しいロックを取得します。

つまり、ロックはありません。

補足として-なぜロックステートメントを使用しないのですか? グローバル ロック オブジェクトは引き続き必要です。

于 2009-10-23T18:23:53.493 に答える
1

グローバル変数とローカル変数の理由は、私が理解しているように、LOCKが実際にメモリ内の参照ポイントをロックダウンしているためです。新しいオブジェクト、つまり「Object obj = new object();」をインスタンス化するたびに、メモリ内に独自のポインタを使用して新しいオブジェクトを作成します。したがって、LOCKがメモリ内のポイントがロックダウンされているかどうかを確認する場合、ロックダウンされていません。これはメモリ内のまったく新しい参照ポイントであり、それを使用するのは呼び出し元がプロパティに入るだけだからです。Obj変数をグローバルに宣言すると、それは常にメモリ内の同じポイントになり、ロックは実際に検証できます。実際、メモリ内のそのポイントは現在ロックされているか、自分でロックできます。

例:(粗雑ですが、要点はわかります)

Object obj = new object();

これで、メモリ内に次のようなポイントができました。

メモリー -

    * obj1

ここで、プロパティをもう一度入力して、新しいオブジェクトをもう一度作成します。これで、システムメモリは次のようになります...

メモリー -

   * obj1
   * obj2

最初の旅行で、あなたのロックはメモリ内の「Obj1」をチェックしています。あなたの財産への最初の旅行の発信者はObjのそのインスタンスを使用している唯一の人なので、それをロックしたり、ロックをチェックしたりするのはそれだけです。メモリ内のそのObj参照のコピーを見ているからです。

2回目のトリップでは、ロックはメモリ内の「Obj2」をチェックします。

グローバル変数を使用すると、メモリ内のそのポイントが存続するため、lockは常にメモリ内の同じポイントをチェックします。移動することはなく、常にメモリ内の同じ参照ポイントです。したがって、プロパティのすべての呼び出し元は常にメモリ内の同じ参照ポイントを使用し、期待どおりにロックが成功します。

特記事項:「obj」の存続期間については述べていません。これがマルチスレッドプロセスでどのように機能するかを簡単に述べています。それがお役に立てば幸いです。

于 2009-10-23T19:14:27.743 に答える