2

Say I have a List of values that I accessed by different threads. So I make it thread safe by doing something like this:

private static object syncObject;
syncObject = new Object();

public List<double> MyList
{
    get
    {
        lock(syncObject) { return myList;}
    }   
    set
    {
        lock(syncObject) { myList = value;}
    }
}

If in one of my functions, I need to access the Count attribute of the List, it may not be thread safe anymore. So how do I write it such that even when accessing the attributes, it will be thread safe?

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
John Tan
  • 1,331
  • 1
  • 19
  • 35
  • 4
    This doesn't make the List threadsafe, this synchronizes access to *the property that returns the list*. – Willem van Rumpt Aug 25 '15 at 06:59
  • There are at least two problems. 1) This code doesn't protects `myList` from being accessed in multiple threads. 2) you're using static lock for synchronizing a instance property. There will be unnecessary contention between unrelated instances. – Sriram Sakthivel Aug 25 '15 at 07:02
  • Access `Count` in a multithreaded environment is not a gool idea. The only way might be to return a copy of this list. Maybe you can use this: `get { lock (syncObject) return myList.ToList(); }` and `set { lock (syncObject) myList = value.ToList(); }` or you hide the whole list and synchonizes all accesses to it. – Sebastian Schumann Aug 25 '15 at 07:03

4 Answers4

4

Like Willem van Rumpt said, you just synchronized the access to that specific property, not made it thread safe. To not reinvent the wheel, you can use the collections from System.Collections.Concurrent (https://msdn.microsoft.com/en-us/library/dd267312(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1)

Another more viable option would be to use an immutable list. Unfortunately, afaik .Net doesn't offer too much here. The only implementation I know about is in Microsoft.FSharp.Collections. The list in this namespace is an immutable singly-linked list. (although I haven't used it from C#).

UPDATE: As Matías Fidemraizer noted, there is the System.Collections.Immutable nuget package available for .net 4.5 and above that contains implementations for multiple immutable collections. Thank you!

Community
  • 1
  • 1
Stefan Turcanu
  • 904
  • 9
  • 13
  • 2
    `throw new InvalidStatementException("You said there're no immutable collections while System.Collections.Immutable NuGet pakcage has been around since a lot of months!");` – Matías Fidemraizer Aug 25 '15 at 07:18
  • catch :) I wasn't aware of that namespace, but since it's a nuget package, I don't think it's technically included in .Net. Thank you very much for the headsup! – Stefan Turcanu Aug 25 '15 at 07:22
  • 2
    Well, you know that most of .NET is now distributed as NuGet packages. Maybe System.Collections.Immutable will be part of out-of-the-box .NET vNext BCL – Matías Fidemraizer Aug 25 '15 at 07:24
0

In order to implement your code with thread-safety, you need to lock the collection until you don't need it anymore in some part of your code.

For example:

lock(syncObject)
{
     MyList.Add(23.99);
}

Therefore, whenever some other part of your code tries to acquire a lock, it will wait until the other thread exists the critical/synchronized code.

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
0

You are not doing this right. In your example the lock is released when the get property returns the list.

Instead you could encapsulate the list in a class and make the list private. In that class you can have public methods that manipulates the list and uses the lock like this:

public void A()
{
    lock (syncObject)
    {
    // do something here
    }
}

This will ensure only one thread can work on the list at a time.

larsbj1988
  • 16
  • 4
0

I agree that its best never to reinvent the wheel, but just incase you are working on an old .Net version like 2.0 where System.Collections.Concurrent is unavailable, you may follow a different paradigm -

So you never expose the list to the outside world but only the operations & these operations can be made mutually exclusive by adding locks. For example

public void AddToCollection(double value)
{   
    lock(syncObject)
    {
        myList.Add(value);
    }    
}

public int Count
{
   lock (syncObject)
   {
      myList.Count;
   }
}
Kapoor
  • 1,388
  • 11
  • 21