Jayden
Jayden

Reputation: 13

Multithreading sharing counter and List collection variables

Scenario, I am having multiple threads trying to sharing a static global variable counter. After which I would add it into a List of integers and this list would be used in another thread to check out some details.

I realized after even using LOCK on the global variable counter, I still get duplicate numbers

Please pardon my explanation, codes would speak more.

Problem would be different threads may be generated a same counter value( which I don't want). I want a running number without duplicates

class Test
{
    private Object _thisLock = new Object();
    List<int> listing = new List<int>(); //shared LIST

    public void Main()
    {
        //array of threads
        for (int i = 0; i < 8; i++)
        {
            Thread th = new Thread(Work);
            th.Name = "Thread" + i;
            th.Start();
        }
        Thread.Sleep(5000);
        //Start checking for duplicates
        Thread checker = new Thread(Checker);
        checker.Start();
    }

    private void Work()
    {
        Object _thisLock = new Object();
        while (true)
        {
            int a = Singleton.Instance.Counter++;
            Console.WriteLine(Thread.CurrentThread.Name);
            Console.WriteLine("WOrk : " + a);
            lock (_thisLock)
            {
                listing.Add(a);
            }
            Thread.Sleep(1000);
        }
    }

    private void Checker()
    {
        Object _thisLock = new Object();
        while (true)
        {
            lock (_thisLock)
            {
                List<int> selflist = new List<int>();
                selflist.AddRange(listing); ;

                foreach (int p in selflist)
                {

                    if (selflist.FindAll(item => item.Equals(p)).Count() > 1)
                    {
                        Console.WriteLine("Check!!!!!!!!!!!!!!!!!! : " + p);
                    }
                }
            }


            Thread.Sleep(5000);
        }
    }
}

static void Main()
{
    Test t = new Test();
    t.Main();
}

public sealed class Singleton
{
    private static volatile Singleton instance;
    private static object syncRoot = new Object();
    private readonly Object _thisLock = new Object();

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                        instance = new Singleton();
                }
            }

            return instance;
        }
    }
    private volatile static int _counter;
    public int Counter
    {
        get
        {
            lock (_thisLock)
            {
                return _counter;
            }
        }
        set
        {
            lock (_thisLock)
            {
                _counter = value;
            }
        }
    }
}

Upvotes: 1

Views: 180

Answers (2)

opewix
opewix

Reputation: 5083

In your Work method every thread have it's own lock object _thisLock. Remove this statement in your work method and let it use private lockobject of the class:

Object _thisLock = new Object();

Upvotes: 4

Patrick Hofman
Patrick Hofman

Reputation: 156968

Why not just move the counter into the lock and make the lock shared by moving it to the class level?

private object _thisLock = new object();

...

lock (_thisLock)
{
    int a = Singleton.Instance.Counter++;
    listing.Add(a);
}

Also, use a thread safe collection type, like ConcurrentBag.

Upvotes: 2

Related Questions