Designing a Thread Safe Class

前端 未结 6 2145
轮回少年
轮回少年 2021-02-05 11:29

When reading the MSDN documentation it always lets you know if a class is thread safe or not. My question is how do you design a class to be thread safe? I am not talking about

相关标签:
6条回答
  • 2021-02-05 12:09

    Thread safe classes is all about protecting the data (instance variables) in your class. The most common way to do that is to use the lock keyword. The most common newbie mistake is to use lock the entire class instead of a more finegrained lock:

    lock (this)
    {
       //do somethnig
    }
    

    The problem with that is that it can give you a major performance hit if the class does something important. The general rule is to lock as little as possible as short time as possible.

    You can read more here: lock keyword in C#

    When you have strarted to understand multithreadnig more deeply you can also take a look at ReaderWriterLoch and Semaphore. But I suggest you only start with the lock keyword.

    0 讨论(0)
  • 2021-02-05 12:10

    non generic ICollection classes provide properties for thread safety. IsSynchronized and SyncRoot. unfortunately you cannot set IsSynchronized. You can read more about them here

    In your classes you can have something simlar to IsSynchronized and Syncroot , expose public methods/properties alone and inside method body check for them. Your IsSynchronized will be a readonly property, so once your instance is initialized, you will not be able to modify it

    bool synchronized = true;
    var collection = new MyCustomCollection(synchronized);
    var results = collection.DoSomething();
    
    public class MyCustomCollection 
    {
      public readonly bool IsSynchronized;
      public MyCustomCollection(bool synchronized)
      {
       IsSynchronized = synchronized
      }
    
      public ICollection DoSomething()
      { 
        //am wondering if there is a better way to do it without using if/else
        if(IsSynchronized)
        {
         lock(SyncRoot)
         {
           MyPrivateMethodToDoSomething();
         }
        }
        else
        {
          MyPrivateMethodToDoSomething();
        }
    
      }
    }
    

    You can read more about writing thread safe collections on Jared Parson's blog

    0 讨论(0)
  • 2021-02-05 12:15

    In addition to the other excellent answers here, consider another angle as well.

    It isn't enough that the internal data structure of the class is 100% thread safe if the public API has multi-step operations that cannot be used in a thread-safe manner.

    Consider a list class that has been built such that no matter how many threads are doing no matter how many types of operations on it, the internal data structure of the list will always be consistent and OK.

    Consider this code:

    if (list.Count > 0)
    {
        var item = list[0];
    }
    

    The problem here is that between the reading of the Count property and the reading of the first element through the [0] indexer, another thread might have cleared out the contents of the list.

    This type of thread safety is usually forgotten when the public API is created. Here, the only solution is for the calling code to manually lock on something on each such type of access to prevent the code from crashing.

    One way to solve this would be for the list type author to consider typical usage scenarios and add the appropriate methods to the type:

    public bool TryGetFirstElement(out T element)
    

    then you would have:

    T element;
    if (list.TryGetFirstElement(out element))
    {
        ....
    

    presumably, TryGetFirstElement works in a thread-safe manner, and would never return true at the same time as it is not able to read the first element value.

    0 讨论(0)
  • 2021-02-05 12:19

    The easiest and most foolproof way of making a class thread safe is to make it immutable. The beauty of it is that you don't ever have to bother with locking again.

    Recipe: Make all instance variables readonly in C# (final in Java).

    • An immutable object, once created and initialized in the constructor, cannot change.
    • An immutable object is thread safe. Period.
    • This is not the same as having a class with only constants.
    • For mutable parts of your system, you still need to account for and handle locking/synchronization property. This is one reason to write immutable classes in the first place.

    See this question as well.

    0 讨论(0)
  • 2021-02-05 12:20

    To state that the class is thread safe, you are assserting that the internal data structures in the class won't be corrupted through concurrent access by multiple threads. To make that assertion, you would need to introduce locking (synchronize in Java) around critical sections of code within the class which could potentially lead to corruption of they were executed by multiple concurrent threads.

    0 讨论(0)
  • 2021-02-05 12:28

    The documentation doesn't suggest that classes are thread-safe, only methods are. In order to assert that a method is thread-safe, it has to be callable from multiple threads simultaneously without giving incorrect results (where incorrect results would be the method returning the wrong value or the object getting into an invalid state).

    When the documentation says

    Any public static (Shared in Visual Basic) members of this type are thread safe.

    it probably means that the static members of the class do not mutate shared state.

    When the documentation says

    Any instance members are not guaranteed to be thread safe.

    it probably means that methods have minimal internal locking.

    When the documentation says

    All public and protected members of this class are thread-safe and may be used concurrently from multiple threads.

    it probably means that all methods you can call use the appropriate locking within them. It is also possible that the methods do not mutate any shared state, or that it is a lock-free data structure that by-design allows concurrent usage without any locks.

    0 讨论(0)
提交回复
热议问题