最近在做windows runtime下APP开发的工作。在Service层请求返回后,往往会通过回调的形式来通知UI更新数据。多个线程操作经常出现foreach抛出异常:System.InvalidOperationException: 集合已修改;可能无法执行枚举操作,导致APP crash。

  在网上搜索了一下,得出以下结论:

  1.   实现一个真正线程安全的List是很困难的,具体可以参考这篇Why are thread safe collections so hard?。
  2.   使用ConcurrentBag<T>,微软给出的线程安全的集合,缺点是unordered。如果集合依赖内部元素的顺序,就不太合适了。
  3.   实现一个枚举安全的List,所需的工作量相对小很多,甚至仅需要给已用到的List操作加上lock。

  以下是一个最小化实现的枚举安全的List。因为实际工程中,需要枚举安全的集合仅用到了Add,Count,索引等操作,所以继承了IEnumerable接口,而不是IList。同时也不影响使用Linq to objects的扩展方法,真是偷了一个大懒。

    class EnumerationSafeList<T> : IEnumerable<T>
{
private List<T> innerList = new List<T>(); private object lockObject = new object(); public IEnumerator<T> GetEnumerator()
{
return Clone().GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator()
{
return Clone().GetEnumerator();
} public void Add(T item)
{
lock(lockObject)
{
innerList.Add(item);
}
} public void Remove(T item)
{
lock(lockObject)
{
innerList.Remove(item);
}
} public int Count
{
get
{
lock(lockObject)
{
return innerList.Count;
}
}
} public T this[int index]
{
get
{
lock(lockObject)
{
return innerList[index];
}
}
set
{
lock(lockObject)
{
innerList[index] = value;
}
}
} private List<T> Clone()
{
var cloneList = new List<T>();
lock(lockObject)
{
foreach (var item in innerList)
{
cloneList.Add(item);
}
}
return cloneList;
}
}

  代码对Add,Remove,Count和索引四个操作加了lock,同时在枚举时通过加lock并返回当前集合的副本,来避免遍历时因为其他线程的修改而抛出异常。

  如果代码需要List类型的全部方法,就需要进一步修改,把IEnumerable改成IList并实现接口,就可以得到一个完整的“data thread safe list”。

  完整的代码及测试用的程序:代码

最新文章

  1. 针对github权限导致hexo部署失败的解决方案
  2. 编译器工具 Flex Bison for Windows 简单入门例子
  3. mysql 三种恢复方式
  4. 苹果手机 微信调用百度地图Javascript API 频繁闪退问题
  5. 耦合 Coupling the object-oriented paradigm &amp;&amp; data coupling
  6. ListView 使用详解
  7. MapReduce编程系列 — 6:多表关联
  8. C# using Sendkey function to send a key to another application
  9. java中 引用类型 和 基本类型 有何区别?
  10. [工作问题总结]MyEclipse 注册
  11. Android ReceiverCallNotAllowedException: BroadcastReceiver components are not allowed to register to receive intents
  12. JAVA中反射机制一
  13. linux命令 uname -r 和 uname -a 的解释与演示
  14. BZOJ_4872_[Shoi2017]分手是祝愿_概率与期望
  15. 正则表达式(Regular expressions)使用笔记
  16. Go中的iota
  17. Hive参数的临时设置和永久性设置
  18. 莫名其妙的标记之@noescape
  19. 几个常用的Eclipse插件
  20. 数据库ADO方式读取图片

热门文章

  1. IOS 上传ipa文件失败
  2. Maven(四-2) Maven pom.xml 配置详解
  3. 新手C#异常的学习2018.08.07
  4. ORA-01157:无法标识/锁定数据文件,ORA-01110:数据文件。。。
  5. Linux安装centos7
  6. 2015年传智播客JavaEE 第168期就业班视频教程17-登录功能业务逻辑实现(代码)
  7. ampify shader工具学习一
  8. iOS正确解决隐藏导航栏后push和pop或dismiss和present闪黑问题
  9. MVC页面和表单
  10. FIX protocol tutorial : Fix Session is not connecting how to diagnose it ?