列出线程问题

时间:2012-05-01 18:38:10

标签: c# c#-4.0 concurrency

我正在尝试使我的应用程序线程安全。我举起手来承认我是新手,所以不知道该怎么办。

为了提供简化版本,我的应用程序包含一个列表。

  • 大多数应用程序访问此列表但不会更改它 可以通过它列举。所有这些都发生在UI线程上。
  • 螺纹 一个人会定期查找要添加和删除的项目 列表。
  • 线程2将枚举列表并使用更新项目 额外的信息。这必须与第一个线程同时运行 可以采取从几秒到几小时的任何事情。

第一个问题是,是否有人为此推荐过滤。

其次,我试图制作主要应用程序将使用的列表的单独副本,在更新/添加或删除某些内容时定期获取新副本,但这似乎不起作用。

我有我的清单和副本......

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

如果我获得copyList,修改它,保存主列表,重新启动我的应用程序,加载主列表并再次查看copylist然后存在更改。我认为我做错了,因为copylist似乎仍然指的是主列表。

我不确定它是否有所作为,但所有内容都是通过类的静态实例访问的。

public static MDGlobalObjects CacheObjects = new MDGlobalObjects();

3 个答案:

答案 0 :(得分:1)

actly copylist只是mainList的浅层副本。列表是新的,但列表中包含的对象的引用仍然是相同的。为了实现您的目标,您必须制作列表的深层副本 像这样的东西

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

并像

一样使用它
return mainList.Clone();

答案 1 :(得分: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);
}

答案 2 :(得分: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中,如果您可以设置属性,以便在每次原子写入后整个对象保持一致,那么您可以跳过制作副本,只需使用集合中的对象填充属性。

此代码中存在一些竞争条件,但它们应该是良性的,因为读者始终对集合有一致的视图。