1

アプリケーションスレッドを安全にしようとしています。私は手を上げて、糸脱毛に慣れていないことを認めているので、どのように進めればよいかわかりません。

簡略化したバージョンを提供するために、私のアプリケーションにはリストが含まれています。

  • ほとんどのアプリケーションはこのリストにアクセスし、それを変更しませんが、リストを介して列挙する場合があります。これはすべてUIスレッドで発生します。
  • スレッド1は、リストに追加および削除するアイテムを定期的に検索します。
  • スレッド2はリストを列挙し、追加情報でアイテムを更新します。これはスレッド1と同時に実行する必要があり、数秒から数時間かかる場合があります。

最初の質問は、誰もがこれに対して推奨されるストラジーを持っているかどうかです。

次に、メインアプリケーションが使用するリストのコピーを個別に作成し、何かが更新/追加または削除されたときに定期的に新しいコピーを取得しようとしましたが、これは機能していないようです。

私は私のリストとコピーを持っています......

public class MDGlobalObjects
{
    public List<T> mainList= new List<T>();
    public List<T> copyList
    {
        get
        {
            return new List<T>(mainList);
        }
    }
}

copyListを取得し、それを変更し、メインリストを保存し、アプリケーションを再起動し、メインリストをロードして、コピーリストをもう一度見ると、変更が存在します。コピーリストはまだメインリストを参照しているように見えるので、私は何か間違ったことをしたと思います。

違いがあるかどうかはわかりませんが、クラスの静的インスタンスを介してすべてにアクセスします。

public static MDGlobalObjects CacheObjects = new MDGlobalObjects();
4

3 に答える 3

1

実際のコピーリストは、mainListの浅いコピーにすぎません。リストは新しいものですが、リストに含まれるオブジェクトの参照は同じです。あなたがしようとしていることを達成するために、あなたはこのようなリストの深いコピーを作らなければなりません

public static IEnumerable<T> Clone<T>(this IEnumerable<T> collection) where T : ICloneable
{
    return collection.Select(item => (T)item.Clone());
}

のように使用します

return mainList.Clone();
于 2012-05-01T18:45:13.057 に答える
1

あなたの質問をもう一度見て..全体的なアプローチの変更を提案したいと思います。を使用ConcurrentDictionary()しているように使用する必要があります.Net 4.0。並行コレクションとしてロックを使用する必要がないという点で、常に有効な状態が維持されます。
コードは次のようになります。

Thread 1s code --- <br>
var object = download_the_object();
dic.TryAdd("SomeUniqueKeyOfTheObject",object);
//try add will return false so implement some sort of retry mechanism

Thread 2s code
foreach(var item in Dictionary)
{
 var object item.Value;
var extraInfo = downloadExtraInfoforObject(object);
//update object by using Update
dictionary.TryUpdate(object.uniqueKey,"somenewobjectWithExtraInfoAdded",object);
}
于 2012-05-01T19:51:04.210 に答える
1

これはConcurrentDictionaryを使用した要点です:


public class Element
{
    public string Key { get; set; }
    public string Property { get; set; }

    public Element CreateCopy()
    {
        return new Element
        {
            Key = this.Key,
            Property = this.Property,
        };
    }
}

var d = new ConcurrentDictionary<string, Element>();

// thread 1
// prune
foreach ( var kv in d )
{
    if ( kv.Value.Property == "ToBeRemoved" )
    {
        Element dummy = null;
        d.TryRemove( kv.Key, out dummy );
    }
}

// thread 1
// add
Element toBeAdded = new Element();
// set basic properties here
d.TryAdd( toBeAdded.Key, toBeAdded );

// thread 2
// populate element
Element unPopulated = null;
if ( d.TryGetValue( "ToBePopulated", out unPopulated ) )
{
    Element nowPopulated = unPopulated.CreateCopy();

    nowPopulated.Property = "Populated";

    // either
    d.TryUpdate( unPopulated.Key, nowPopulated, unPopulated );

    // or
    d.AddOrUpdate( unPopulated.Key, nowPopulated, ( key, value ) => nowPopulated );
}

// read threads
// enumerate
foreach ( Element element in d.Values )
{
    // do something with each element
}

// read threads
// try to get specific element
Element specific = null;
if ( d.TryGetValue( "SpecificKey", out specific ) )
{
    // do something with specific element
}

スレッド 2 では、各アトミック書き込み後にオブジェクト全体の一貫性が保たれるようにプロパティを設定できる場合は、コピーの作成をスキップして、コレクション内のオブジェクトをプロパティに入力するだけでかまいません。

このコードには競合状態がいくつかありますが、リーダーが常にコレクションの一貫したビューを持っているという点で、問題はありません。

于 2012-05-01T20:58:00.077 に答える