21

I have asked a question badly over here Lock on a variable in multiple threads so for clarity I am going to ask it here and hope I can ask it correctly.

classA
  creates instance of classB
  has methodA that can update & uses classB's myVar
  has methodB that can update & uses classB's myVar

classB
  has a variable myVar

methodA and methodB can both run in separate threads (called in new threads from main). How do I ensure this is thread safe?

Community
  • 1
  • 1
SimpleOne
  • 1,066
  • 3
  • 12
  • 29
  • 2
    Based on your other question, you should describe the situation from a higher level because it really feels like you're going in the wrong direction. – Austin Salonen Nov 02 '10 at 21:50

6 Answers6

29

Use the lock keyword to guard code that can be executed simultaneously by more than one thread.

public class ClassA
{
  private ClassB b = new ClassB();

  public void MethodA()
  {
    lock (b)
    {
      // Do anything you want with b here.
    }
  }

  public void MethodB()
  {
    lock (b)
    {
      // Do anything you want with b here.
    }
  }
}

It is important to note that lock does not guard or lock the object instance used in the statement. Instead, the object is used as a way to identify a section of code that should be prevented from executing if another section using the same object instance is already executing. In other words, you could use any object instance you like in the lock statements and it would still be safe to access members of ClassB.

Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
  • 3
    Why would you lock b? Why would you not create a second object called bLock and lock that instead? depending on what b does, you may have created thread unsafe code, there w are no cons from making a second object that I can think of – rollsch Feb 12 '19 at 07:40
3

I've written a blog post about having multiple threads add values to a list and using lock() to prevent the writes from colliding along with why this needs to be done.

Erik Noren
  • 4,279
  • 1
  • 23
  • 29
1

The easiest solution: Don't share the instance of ClassB among your threads.

In other words, instantiate a new ClassB with your thread declaration and send it as a parameter.

Austin Salonen
  • 49,173
  • 15
  • 109
  • 139
0

Check out the lock statement documentation.

Kon
  • 27,113
  • 11
  • 60
  • 86
0

Unfortunately, the question is somewhat ambiguous about what is considered success in terms of thread safety. Thread safety just means that the operation would work correctly if multiple threads are executing.

What seems to be missing is whether or not classA.methodA or classA.methodB needs to finish its operation with classB.myVar before either another thread calling classA.methodA(...) or classA.methodB(...). It would determine what type of locking pattern you would need.

For example, if you need a guarantee on reading a value, it would look like the following:

public class classA
{
    private classB b = new classB();

    public void methodA()
    {
        lock (b)
        {
            // Operation without calling methodA() or methodB() 
            // Read b.myVar
            // Update b.myVar
        }
    }

    public void methodB()
    {
        lock (b)
        {
            // Operation without calling methodA() or methodB()
            // Read b.myVar
            // Update b.myVar
        }
    }
}

In another example, if b.myVar is some type of collection that needs to be synchronized like a cache, it would look like the following:

public class classA
{
    private classB b = new classB();

    public void methodA()
    {
        // Read b.myVar for missing collection item

        lock (b)
        {
            // Check for missing collection item again. If not missing, leave lock
            // Operation without calling methodA() or methodB() 
            // Read b.myVar
            // Update b.myVar with new array item
        }
    }

    public void methodB()
    {
        // Read b.myVar for missing collection item
        lock (b)
        {
            // Check for missing collection item again. If not missing, leave lock
            // Operation without calling methodA() or methodB() 
            // Read b.myVar
            // Update b.myVar with new array item
        }
    }
}
Frank Liao
  • 641
  • 1
  • 6
  • 9
  • The second code block is unsafe. A read of `b.myVar` could occur simultaneously with a write to `b.myVar` if you attempt to perform the read outside of the lock. – Brian Gideon Jul 16 '14 at 23:56
  • Why would you lock b? Why would you not create a second object called bLock and lock that instead? As said above this is not thread safe. – rollsch Feb 12 '19 at 07:39
-1

ClassB shouldn't be exposing a variable (by which you probably mean data member). Expose a property or set of methods instead, and use ReaderWriterLockSlim to handle multiple threads.

  • Recommendation for that class is premature given the dearth of info in the questions, imo – Steve Townsend Nov 02 '10 at 23:05
  • You can (and should) do your own benchmarks, but I think you will find that `ReaderWriterLockSlim` will be up to 5x slower than a plain old `lock` in this case. – Brian Gideon Nov 03 '10 at 02:06