Eitan
Eitan

Reputation: 1504

Simple threading question, locking non local changes

Ok first I must preface this question with a disclaimer, I'm really new to threading so this may be a 'newbie' question but I searched google and couldn't find an answer. As I understand it a critical section is code that can be accessed by two or more threads, the danger being one thread will overwrite a value before the other is finished and vice versa. What can you do about changes made outside of your class for example, I have a line monitoring program:

int currentNumber = provider.GetCurrentNumber();
if(provider.CanPassNumber(false, currentNumber))
{
currentNumber++;
provider.SetNumber(currentNumber);
}

and on another thread I have something like this:

if(condition)
    provider.SetNumber(numberToSet);

Now I'm afraid that in the first function I get currentNumber which is 5, right after that on another thread the number is set to 7 and then it rewrites the 7 to 6, ignoring the change made by the thread that set it to 7.

Is there anyway to lock provider.SetNumber until the first function finishes? The critical section is basically the currentNumber which can be changed by many places in the program.

I hope I made myself clear, if not let me know and I will try to explain myself better.

EDIT: Also I made the functions really short for the example. In reality the function is much longer and makes changes to currentNumber many times so I don't really want to put a lock around the entire function. If I lock every call to provider.SetNumber and release it after I finish it can change during the time it is released before I lock it again to call provider.SetNumber. Honestly I'm also worried about locking the entire function because of performance and deadlock.

Upvotes: 0

Views: 210

Answers (6)

Peter
Peter

Reputation: 38515

Well first of im not so good with threading but a critical section is a part of your code that can only be accessed my one thread at a time not the other way around..

To create a critical section is easy

Lock(this)
{
    //Only one thread can run this at a time
}

note: that this should be replaced with some internal object...

Upvotes: 0

Ian
Ian

Reputation: 34509

Rather than using the lock() keywords I'd suggested seeing if you can use the Interlocked class which is designed for small operations. It's got much less overhead than lock, in fact can be down to a single CPU instruction on some CPUs.

There are a couple of methods of interest for you, Exchange and Read, both of which are thread safe.

Upvotes: 2

bitxwise
bitxwise

Reputation: 3594

In your SetNumber method you can simply use a lock statement:

public class MyProvider {
     object numberLock = new object();
     ...
     public void SetNumber(int num) {
          lock(numberLock) {
               // Do Stuff
          }
     }
}

Also, note that in your example currentNumber is a primitive (int), which means that variable's value won't be overwritten should your provider's actual data member's value change.

Upvotes: 0

Nekresh
Nekresh

Reputation: 2988

You can use the lock statement, to enter a critical section with mutual exclusion. The lock will use the object's reference to differentiate one critical section from another, you must have the same reference for all your lock if it accesses to the same elements.

// Define an object which can be locked in your class.
object locker = new object();

// Add around your critical sections the following :
lock (locker) { /* ... */ }

That will change your code to :

int currentNumber = provider.GetCurrentNumber();

lock (locker)
{
  if(provider.CanPassNumber(false, currentNumber))
  {
    currentNumber++;
    provider.SetNumber(currentNumber);
  }
}

And :

if(condition)
{
  lock (locker)
  {
    provider.SetNumber(numberToSet);
  }
}

Upvotes: 0

Rob
Rob

Reputation: 27367

As Filip said, lock is useful here. Not only should you lock on provider.SetNumber(currentNumber), you also need to lock on any conditional that the setter depends on.

lock(someObject)
{
  if(provider.CanPassNumber(false, currentNumber))
  {
    currentNumber++;
    provider.SetNumber(currentNumber);
  }
}

as well as

if(condition)
{
  lock(someObject)
  {
    provider.SetNumber(numberToSet);
  }
}

If condition is reliant on numberToSet, you should take the lock statement around the whole block. Also note that someObject must be the same object.

Upvotes: 0

Filip Ekberg
Filip Ekberg

Reputation: 36297

You want to look into the Lock keyword. Also you might want to this tutorial to Threading in C#.

Upvotes: 0

Related Questions