3
abstract class Foo
{
    private List<Object> container;
    private bool update;

    Foo Foo()
    {
        container = new List<object>();
        update = false;
    }

    public abstract Bar CreateBar();

    public void BeginUpdate()
    {
        if (!update)
        {
            Thread update_thread = new Thread(new ThreadStart(Update));
            update_thread.Start();
        }
    }

    private void Update()
    {
        update = true;
        while (update)
        {
            lock (container)
            {
                if (...)
                    container.Add(this.CreateBar());
                else
                    container.Remove(...);
            }

            Thread.Sleep(1337);
        }
    }

    public void EndUpdate()
    {
        update = false;
    }

    public List<Object> Objects
    {
        get
        {
            lock (container)
            {
                return this.container;
            }
        }
    }
}

Fooの外部の何かがFooのオブジェクトアクセサーを次のように呼び出すと、

List<Objects> objects = foo_instance.Objects;
foreach (Object o in objects)
{
    Thread.Sleep(31173);
}

ロックはどのように発生しますか?Update()を実行しているスレッドは、上記のforeachがオブジェクトリストの処理を完了するまで待機する必要がありますか?これら2つが同時に機能することを望みますが、オブジェクトのディープコピーを作成する唯一の解決策はありますか?

4

4 に答える 4

3

このコードに関するいくつかの問題:

  1. スレッドを開始しません
  2. 複数のスレッドがBeginUpdateを呼び出し、両方が更新がfalseであると認識し、両方がスレッドを開始する競合状態(プログラムに適用できない場合があります)を設定できます。これで、2つのスレッドが実行され、互いに干渉している可能性があります。共有データを持つフィールドメンバーがいる
  3. プロパティをロックするポイントは何ですか?あなたはそれを必要としません。プロパティから返すコンテナは、内部更新のために流動的な状態になる場合があることに注意してください。これは、プロパティを呼び出す外部コードが、そのコンテンツにアクセスする前にコンテナ自体をロックする必要があることを意味します。ただし、コンテナ参照を返すためにロックは必要ありません。
  4. EndUpdateを呼び出してからBeginUpdateを次々に呼び出すと、競合状態が発生します。古いスレッドはまだ終了する機会がなかった可能性があります。

何をいつロックするかを心配する前に、他のスレッド関連の問題が多くないようにコードを修正する必要があると思います。

于 2008-11-28T18:00:21.887 に答える
2

あなたのコードはあなたが思っていることをしません。この方法

public List<Object> Objects
{
    get
    {
        lock (container)
        {
            return this.container;
        }
    }
}

値を返した後はロックを保持しません。したがって、ループはロックされません。

クラスからコンテナインスタンスを返すことはできません

于 2008-11-28T17:53:54.507 に答える
1

ロックスコープは関数スコープに似ていると考えることができます。アクセサメソッド内でロックを実行すると、中括弧の間でのみロックされます。値が返されると、ロックが解除されます。目的の効果を得るには、クラスの外部(呼び出し元)でロックを行う必要があります。

したがって、ループとスレッドの両方が同時にオブジェクトにアクセスできるようになります。ループ中にスレッドがオブジェクトを変更すると、コレクションが変更されたためにループが例外をスローするため、これは悪いことです。

于 2008-11-28T17:53:26.410 に答える
0

krosenvaldは正しいです。プロパティがコンテナオブジェクトへのポインタを返すとすぐに、Objectsアクセサのロックが解除されます。

あなたのコードで

List<Objects> objects = foo_instance.Objects;
foreach (Object o in objects)
{    
    Thread.Sleep(31173);
}

ロックは最初の行の間だけ持続します...参照変数"objects"が入力されている場所...ポインタをフェッチすることによってメモリが変更されていないため、その行に対して何もロックする必要はありません...

于 2008-11-28T18:01:28.343 に答える