为了账号安全,请及时绑定邮箱和手机立即绑定

为什么循环遍历时有时候会发生错误呢?怎么解决?

为什么循环遍历时有时候会发生错误呢?怎么解决?

C#
芜湖不芜 2023-03-03 17:13:12
多线程中访问public List<Entity> Entities { get { lock(syncObjecct){return ....}} set{ lock(syncObject){....}}; Entities对象时,为什么循环遍历时有时候会发生错误(Note: 我已经加锁对象并且用for循环而不是foreach循环访问对象)。我的程序:private List<Entity> entities = new List<Entities>();public List<Entity> Entities { get { lock(syncObjecct){return ...entities.}} set{ lock(syncObject){....entities = value}}; private void Insert(Entity entity){Entities.add(entity);}private void Remove(){if (Entityes.Count >0 )Entities.Remove(0);}int main(){//多个线程添加删除访问Entities链表时候遍历有时会发生错误for (int i = 0; i <Entities.Count;i++)  {var item = Entities[0]; //报错:集合已经被修改 }}
查看完整描述

1 回答

?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

)【异常的原因】

按您给出的代码,问题出在public List<Entity> Entities{get; set;}上:这个属性方法在获取List<Entity>实例的执行过程中利用了lock(){}来保持同步;但是,一旦这个属性方法执行结束就跳出了lock(){}的同步范围。这意味着:在主函数中所获取的List<Entity>实例已经不再受到lock的保护了!遍历集合发生将抛出异常(通常是“集合序数变化……”之类的异常)

2)【解决方法】

关键是为遍历集合的方法提供同步功能。见下面的代码


using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Threading; namespace ConsoleApplication1{    class Program    {        static EntityList list = new EntityList();        static void Main(string[] args)        {            //启动线程:向集合中添加            Thread threadAdding = new Thread(Adding);            threadAdding.IsBackground = true;            threadAdding.Start();            //启动线程:从集合中删除            Thread threadRemoving = new Thread(Removing);            threadRemoving.IsBackground = true;            threadRemoving.Start();            //启动线程:遍历集合            Thread threadWork = new Thread(Work);            threadWork.IsBackground = true;            threadWork.Start();             Console.ReadKey();        }         static void Adding()        {            int id = 0;            while (true)            {                id++;                list.Insert(new Entity()                                                 Id = id,                             Gender = "Male"                            Name = "Someone" + id.ToString()                     });                Thread.Sleep(750);            }        }        static void Removing()        {            while (true)            {                list.Remove();                Thread.Sleep(1000);            }        }        static void Work()        {            while (true)            {                //遍历集合                foreach (var in list)                {                    Console.WriteLine(e.ToString());                }                Console.WriteLine("------------");                Thread.Sleep(1000);            }        }    }     /// <summary>    /// 实体对象    /// </summary>    class Entity    {        public int Id { getset; }        public string Name { getset; }        public string Gender { getset; }        public override string ToString()        {            return string.Format(                "Id={0} Name={1} Gender={2}", Id, Name, Gender            );        }    }     /// <summary>    /// 实体对象列表(集合)    /// </summary>    class EntityList : IEnumerable<Entity>    {        object syncObject = new object();        List<Entity> list = new List<Entity>();        public void Insert(Entity entity)        {            lock (syncObject)            {                list.Add(entity);            }        }        public void Remove()        {            lock (syncObject)            {                if (list.Count > 0) list.RemoveAt(0);            }        }        //带同步功能的集合遍历接口        public IEnumerator<Entity> GetEnumerator()        {            lock (syncObject)            {                foreach (var in list)                {                    yield return v;                }            }        }        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()        {            return this.GetEnumerator();        }    }}

 


查看完整回答
反对 回复 2023-03-06
  • 1 回答
  • 0 关注
  • 67 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信