Making class fields thread-safe

有些话、适合烂在心里 提交于 2021-01-28 04:00:55

问题


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?


回答1:


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!




回答2:


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.




回答3:


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.




回答4:


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


来源:https://stackoverflow.com/questions/32197354/making-class-fields-thread-safe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!