5

我修改了枚举集合,但是,我在它周围加了锁……它不明白为什么我得到“集合已修改;枚举操作可能无法执行”。我不想解决它:“foreach(_observers.ToList()中的IObserver obs)”

代码是观察者模式:

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);
        }
    }
}

谁能帮我?谢谢...

4

3 回答 3

2

当您的 Obj2 在此 foreach 循环中调用 Update 时,它​​将返回您的 Subject 对象并在同一线程中修改此 _observers 集合。这就是锁不起作用的原因。这不是同步问题。您的问题发生在同一个线程中。

我不确定您在这段代码中要做什么,所以我无法提供进一步的帮助。

于 2012-12-15T15:10:06.717 回答
1

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

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

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

于 2012-12-15T14:44:30.980 回答
1

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

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

for (int i = _observers.Count-1; i >= 0; i--) {
        _observers[i].Update(sentData);
}                
于 2012-12-15T13:38:08.110 回答