当我在c#中使用Lock时,为什么我得到:“集合被修改;枚举操作可能无法执行。”

时间:2012-12-15 13:31:42

标签: c#

我修改了枚举的集合但是,我把Lock放在它周围...... 它并没有说明我为什么会这样做 “集合已被修改;枚举操作可能无法执行。” 我不想解决它:“foreach(IObserver obs in _observers.ToList())”

代码是观察者模式:

class Program
{
    static void Main(string[] args)
    {
        Subject sub = new Subject();
        Obs1 obs1 = new Obs1(sub);
        Obs2 obs2 = new Obs2(sub);

        sub.Nodefiy();
        sub.Nodefiy();
        sub.Nodefiy();
        sub.Nodefiy();
        sub.Nodefiy();
        sub.Nodefiy();

        Console.ReadKey();
    }
}

public interface IObserver
{
    void Update(int data);
}

public interface ISubscrib
{
    void Reg(IObserver obs);
    void UnReg(IObserver obs);
    void Nodefiy();
}

public class Subject : ISubscrib
{
    private static Object _lock;
    private List<IObserver> _observers;
    private int data = 0;

    public Subject()
    {
        _lock = new Object();
        _observers = new List<IObserver>();
    }

    public void Reg(IObserver obs)
    {
        lock (_lock)
        {
            _observers.Add(obs);
        }
    }

    public void UnReg(IObserver obs)
    {
        lock (_lock)
        {
            int ind = _observers.IndexOf(obs);
            if (ind >= 0)
            {
                _observers.RemoveAt(ind);
            }
        }
    }

    public void Nodefiy()
    {
        data = data + 1;
        lock (_lock)
        {
            int sentData = data;
            //foreach (IObserver obs in _observers.ToList<IObserver>())
            foreach (IObserver obs in _observers)
            {
                obs.Update(sentData);
            }
        }
    }
}

public class Obs1 : IObserver
{
    private ISubscrib _subj;
    public Obs1(ISubscrib subj)
    {
        _subj = subj;
        _subj.Reg(this);
    }

    public void Update(int data)
    {
        Console.WriteLine("Obs1: {0}", data);
    }
}

public class Obs2 : IObserver
{
    private ISubscrib _subj;

    public Obs2(ISubscrib subj)
    {
        _subj = subj;
        _subj.Reg(this);
    }

    public void Update(int data)
    {
        Console.WriteLine("Obs2: {0}", data);
        if (data > 3)
        {
            _subj.UnReg(this);
        }
    }
}
谁能帮助我吗? 感谢...

3 个答案:

答案 0 :(得分:2)

当你的Obj2在这个foreach循环中调用Update时,它将回到你的Subject对象并在同一个线程中修改这个_observers集合。这就是锁无法正常工作的原因。这不是同步问题。你的问题发生在同一个线程中。

我不确定您在此代码中尝试做什么,所以我无法继续帮助。

答案 1 :(得分:1)

锁与线程同步有关,我不确定为什么你认为这会对你有所帮助。

当您正在修改该集合时,您无法枚举集合(请参阅所有相关问题)。将你的foreach更改为:

for (int i = _observers.Count-1; i >= 0; i--) {
        _observers[i].Update(sentData);
}                

答案 2 :(得分:1)

问题是我认为......当您迭代_observers列表时,您还可以从另一个线程添加或修改该集合。

你可以同步线程,你应该这样做,因为如果你试图访问一个被删除的观察者,即使是像索引器一样使用for的解决方案也无济于事。

尝试查看Mutexes以实现一种方式,当一个线程迭代通过集合时,另一个线程将等到它完成后再修改集合。