列出线程问题
本文关键字:问题 线程 | 更新日期: 2023-09-27 18:32:46
我正在尝试使我的应用程序线程安全。 我举起双手,承认我是线程新手,所以不知道该怎么做。
为了给出简化版本,我的应用程序包含一个列表。
- 大多数应用程序访问此列表并且不会更改它,但是可以通过它枚举。所有这些都发生在 UI 线程上。
- 线一个人将定期查找要从列表。
- 线程 2 将枚举列表并更新项目额外信息。 这必须与线程 1 同时运行可能需要从几秒钟到几小时的任何时间。
第一个问题是,有没有人对此有推荐的流浪者。
其次,我试图制作主应用程序将使用的列表的单独副本,在更新/添加或删除某些内容时定期获取新副本,但这似乎不起作用。
我有我的清单和一份副本...
public class MDGlobalObjects
{
public List<T> mainList= new List<T>();
public List<T> copyList
{
get
{
return new List<T>(mainList);
}
}
}
如果我得到 copyList,修改它,保存主列表,重新启动我的应用程序,加载主列表并再次查看 copylist,然后更改就存在。我想我做错了什么,因为复制列表似乎仍然引用主列表。
我不确定它是否有区别,但所有内容都是通过类的静态实例访问的。
public static MDGlobalObjects CacheObjects = new MDGlobalObjects();
这是使用 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 中,如果可以设置属性以使整个对象在每次原子写入后保持一致,则可以跳过创建副本,而只需使用集合中的对象填充属性。
此代码中有一些争用条件,但它们应该是良性的,因为读者始终对集合具有一致的视图。
实际上 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();
再次查看您的问题.. 我想建议整体改变方法。您应该像使用 .Net 4.0
一样使用 ConcurrentDictionary()
。因为您不会将锁用作并发集合始终保持有效状态。
所以你的代码将看起来像这样。
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);
}