Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When i'm using Lock in c# why i get: "Collection was modified; enumeration operation may not execute."

Tags:

c#

I modifying the enumerated collection but, i put Lock around it... and it don't understan why i get "Collection was modified; enumeration operation may not execute." i don't want to solve it with: "foreach (IObserver obs in _observers.ToList())"

the code is Observer pattern:

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

can anyone help me? thanks...

like image 442
goniak Avatar asked Oct 06 '22 15:10

goniak


1 Answers

When your Obj2 is invoking Update inside this foreach loop, it is going back to your Subject object and modifying this _observers collection, in the same thread. That's why the lock is not working. This is not a synchronization issue. Your problem is happening in the same thread.

I am not sure what you are trying to do in this code, so I can't help further.

like image 97
Jason Ching Avatar answered Oct 11 '22 11:10

Jason Ching