C# 多线程操作List

u013330547 2014-11-04 11:02:47
C# 多线程操作List<T>,(只用到Add和Remove方法,某些只用到Add,某些线程中可能既调用Add也调用Remove),求解:怎样保证多线程操作集合时,数据能够同步。
MSDN上List<T>类明明说静态的list对象是线程安全的,但是我收到的数据,和理论有很大偏差。
我在操作的时候,加了锁, lock (lockObj)好像也没有什么起色。
...全文
11388 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
於黾 2014-11-04
  • 打赏
  • 举报
回复
引用 15 楼 u013330547 的回复:
回复14楼:我个人觉得您的做法其实是一样的效果,事实也是,我试过。原因是因为其实每个线程只干一件事,要么添加;要么删除再添加。数据的不一致不是因为线程内部,而是源自多线程对统一list对象操作。当然个人见解。
如果每个线程只会添加一条,或删除一条再添加一条,就根本不会出现所谓"数据不一致"的问题啊 贴出你的试验数据,看到底怎么个不一致法
u013330547 2014-11-04
  • 打赏
  • 举报
回复
对2楼道个歉,不好意思,刚将错误原因没有搞明白,现在仔细看了您给的链接,但是List中没有SyncRoot属性,请问如何同步
u013330547 2014-11-04
  • 打赏
  • 举报
回复
现在问题似乎明确了:如何在多线程对同一集合操作时,保持数据的一致性?
u013330547 2014-11-04
  • 打赏
  • 举报
回复
回复14楼:我个人觉得您的做法其实是一样的效果,事实也是,我试过。原因是因为其实每个线程只干一件事,要么添加;要么删除再添加。数据的不一致不是因为线程内部,而是源自多线程对统一list对象操作。当然个人见解。
於黾 2014-11-04
  • 打赏
  • 举报
回复
如果你想保持线程操作的一致性 你把lock加到外层去,而不是在每个add的地方 这样一个线程全部add完,另一个才能继续add
u013330547 2014-11-04
  • 打赏
  • 举报
回复
只是个别,很多用户数据已经修改成功,大约每次只会有一到两个,list没有修改
u013330547 2014-11-04
  • 打赏
  • 举报
回复
回复10楼:恩,似乎明白了点什么,长见识了,但如何处理这种多线程操作带来的数据误差呢?比如其中一个线程删除原来的用户(用户数据修改,dll通知),然后添加一个新的用户,但是这个操作dll日志上显示数据已经回调上来,但是list先add,然后remove之后,数据没有得到修改
  • 打赏
  • 举报
回复
不管msdn上说一个方法是不是“线程安全的”,你在多线程编程时(如果需要)都需要编写操作同步代码,这样你才能得到你想要的一致性、不错乱的数据。 “线程安全”跟“多线程数据操作一致性”,确实是“两个不同的概念”。
  • 打赏
  • 举报
回复
一个方法“是线程安全的”,是说它可以保证“走到底”而不抛出异常。比如说你用两个线程同时操作此方法(或者相关方法),如果此方法抛出异常了,那么它就不是线程安全的;而如果结果看起来乱了(但是实际并没有乱,因为并发操作让你不会调试了而已),这不算是线程不安全。 有人说“线程安全”就代表着多线程操作时结果不会乱,这是错误的。“线程安全”跟结果会不会错乱并没有关系。因为结果错乱,其实是一个“正常的业务结果”,人家的方法内部并没有在运行的半截发现什么“数组大小错误、非法数据”等等崩溃事件,给你一个你认为错乱的数据,这也是线程安全的!
u013330547 2014-11-04
  • 打赏
  • 举报
回复
7楼,那个ConcurrentBag<T>貌似不支持Xp,额,很可能会有麻烦,不知道XP上安装4.0,能否支持?
u013330547 2014-11-04
  • 打赏
  • 举报
回复
回复5楼 我已经将list定义成了静态成员,并不是实例成员,但是问题貌似没有解决
hwangt0 2014-11-04
  • 打赏
  • 举报
回复
引用 6 楼 u013330547 的回复:
用户管理系统 成员声明:(User类实现INotifyPropertyChanged接口) public static List<User> list = new List<User>(); private static object lockObj = new object(); 方法(只能给描述): 有一个调用dll的回调-->每收到一个回调,另起一个线程对List操作,回调个数不确定 二楼的方法,没有办法实现,线程个数完全不知道,由回调给出,什么时候有回调不能确定,有几个也不能确定,三楼的方法,貌似木有起到作用
用用ConcurrentBag<T>试试,这是线程安全的List
u013330547 2014-11-04
  • 打赏
  • 举报
回复
用户管理系统 成员声明:(User类实现INotifyPropertyChanged接口) public static List<User> list = new List<User>(); private static object lockObj = new object(); 方法(只能给描述): 有一个调用dll的回调-->每收到一个回调,另起一个线程对List操作,回调个数不确定 二楼的方法,没有办法实现,线程个数完全不知道,由回调给出,什么时候有回调不能确定,有几个也不能确定,三楼的方法,貌似木有起到作用
phommy 2014-11-04
  • 打赏
  • 举报
回复
线程安全
此类型的公共静态(在 Visual Basic 中为 Shared)成员是线程安全的。但不能保证任何实例成员是线程安全的。

只要不修改该集合,List<T> 就可以同时支持多个阅读器。从头到尾对一个集合进行枚举在本质上不是一个线程安全的过程。在枚举与一个或多个写访问竞争的罕见情况下,确保线程安全的唯一方法是在整个枚举期间锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步。
Add和Remove显然是“实例成员”方法,并不线程安全 既然你不涉及遍历,在Add和Remove时随便找个对象lock了就行了,比如lock(lst) --- 当然,你得保证你的代码逻辑本身是“线程安全”的,lock只是保证List本身操作的完整性
hwangt0 2014-11-04
  • 打赏
  • 举报
回复
或者用ConcurrentBag<T> ,这是线程安全的List<T>
於黾 2014-11-04
  • 打赏
  • 举报
回复
1.首先,线程安全不安全跟线程同步完全是两个概念,那是线程互斥 2.lock (lockObj)中的lockObj,你得保证每个地方用的都是同一个对象,所以最好定义成static型,以免实例化多次
hwangt0 2014-11-04
  • 打赏
  • 举报
回复
http://www.cnblogs.com/GavinCome/archive/2008/04/09/1145250.html 希望能帮助到你
moonwrite 2014-11-04
  • 打赏
  • 举报
回复
贴一点代码结构
software_artisan 2014-11-04
  • 打赏
  • 举报
回复 2
别整什么锁或者同步,看上去高大上,实际很难得到完美的结果。写个委托add和remove的方法简单有效。
u013330547 2014-11-04
  • 打赏
  • 举报
回复
多谢诸位,在同事的帮助下,问题貌似已经解决,但是说实话,我也不知道怎么就解决了,初学C#三个月左右,对多线程操作完全稀里糊涂。诸位有关于线程的资料的话,希望一同分享,谢谢! 最后,结贴。
加载更多回复(2)

110,570

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧