Defensive anti-multithreading class implementation

231 views Asked by At

I have an object that is not safe for multithreaded applications (in several ways), and I want to provide an internal check to make sure that critical methods are not accessed concurrently.

Question

What techniques should I employ to detect and prevent multiple threads from accessing my class?

Is it sufficient to track the Thread.ID on all methods, properties, etc. that the consumer may use?

5

There are 5 answers

0
Val Bakhtin On

Will it help?

lock(_padLock)
{
   ....
}

or if you have your object accessed externally, you could use Mutex object.

3
Brian Rasmussen On

Just document that it isn't thread safe. That's the convention used by the classes in .NET.

0
makerofthings7 On

The attribute MethodImplOptions has an enum for Synchronized

Specifies that the method can be executed by only one thread at a time. Static methods lock on the type, whereas instance methods lock on the instance. Only one thread can execute in any of the instance functions, and only one thread can execute in any of a class's static functions.

...though this is not recommended. This method does the functional equivalent of lock(this) which allows the lock to be taken accidentally or maliciously by other classes

Another option is to use a separate object is used for locking. When doing this it can be marked as readonly, unless it's a struct like Spinlock. In short: don't use the readonly attribute for Spinlock : this cause every call to SpinLock or _lock.Enter to get a new copy of the object and succeed. Corruption is likely if this is done.

  class myClass
  {
      private object myLock;           //OK
      private readonly object myLock2; //OK
      private readonly SpinLock myLock3;  //WARNING: Value type, won't work as intended
      private SpinLock myLock4;  //OK

     void DoStuff()
     {
        lock(myLock4)
        {
           // some quick instructions... say 10 or fewer
        }
     }
  }
1
EtherDragon On

The best internal check you can possibly use is the lock setup that others have suggested. But here are some creative ways worth investigating to see if they solve your specific problem. The issue I have is, I don't know if only parts of the class is unsafe, if it's thread-safe to have different threads using different instances of the class or not. So here are some combinations of lock that mitigate certain scenarios

Scenario 1: Static Class/Methods - This will ensure that no matter who accesses the static class/members they will be blocked if another thread is already doing so.

public static class UnsafeStaticClass
{
    private static object _padLock = new object();

    public static void UnsafeStaticMethod()
    {
        lock(_padLock)
        {
            // Do Work
        }
    }
}

Scenario 2: Normal class where instances can be paralel, but only one call per instance is allowed. Multiple instances can run the code block at the same time.

public class UnsafeClass
{
    private object _padLock = new object();

    public void UnsafeMethod()
    {
        lock(_padLock)
        {
            // Do Work
        }
    }
}

Scenario 3: A Class instance, that interracts with unsafe static methods - hence a need to ensure that only a single call to ouside static methods exists. No matter how many instances there are, only one of them can run the method at a time, since it locks on a static object.

public void UnsafeClass
{
    private static object _padLock = new object();

    public void UnsafeInstanceMethod()
    {
        lock(_padlock)
        {
            // Do Work
        }
    }
}        
0
RalphChapin On

Checking the thread ID's will catch multi-threaded use, in that if someone uses it in a multi-threaded program it will toss out messages that will, hopefully, stop people from using the program. It won't be elegant, but it will alert people to trouble eventually. How the program is used will determine the likelyhood of serious harm being done before people realize their error.

But in general, single-threaded code works really well in multi-threaded programs. It's fast and (relatively) easy to write. (Of course, the calling code has to be very careful.) You would be giving up this capability for your class and limiting it to run only in programs that will take care to run it in one single thread, from the start to the end of the program. In a windows desktop program, for instance, this pretty much means it has to run in the event queue, which means it will necessarily tie up the event queue while it runs--no worker threads!

Most collection classes are single-threaded, but get extensive use in multi-threaded programs. I'd use them as a model for single-threaded coding.