views:

848

answers:

9

In c#, is there a way of updating a variable (without using lock) where multiple threads can read the value, but the thread that updates the variable is not considered important.

What I mean is, the value being updated isnt that important, so if a thread updates that value but the other threads don't get that updated value a few minutes later.

Is there such a way?

Many thanks

+4  A: 

If the updated value is not important to other threads, why the variable is shared between the threads at all? Every thread can use its own copy.

It isn't clear to me. Do you want to intentionally make the delay for reading values or you mean it doesn't matter if other threads can't immediately see the updated value?

In any case, if you want to atomically update a variable without a lock, you should consider using Interlocked methods but I'm not really sure if this is what you need.

Mehrdad Afshari
I'm almost certain he just wants a variable to share between instances of classes (i.e.a `static` variable). But the general idea is certainly quite questionable.
Noon Silk
+1  A: 

This sounds like it might be a roundabout way to re-invent a caching mechanism. Have you looked into any of the many caching systems available for .NET?

Rex M
+4  A: 

It depends on what you're trying to do. You could mark the field volatile but that may not do you any good. I'm not sure if volatile will insure that incrementing is an atomic operation, for instance. In other words, one of your increments (or other updates) might be "lost" (overwritten by another thread). For that you could use Interlocked.Increment.

Again, it really depends on what you're trying to do. Much of the time it's easiest just to use a lock.

TrueWill
A: 

You might want to take a look into System.Threading.AutoResetEvent or System.Threading.ManualResetEvent.

It allows you to trigger events across threads (value changed). ManualResetEvent might be more appropriate if you want to be lazy on updates...

I'm not sure if you're looking into controlling access to a said variable... In that case, a synchornized method could do the trick:

[MethodImpl(MethodImplOptions.Synchronized)]
public void Foo()
{
    // Do foo
}

You can also acquire a lock for the said object when modifying its value:

lock(myObject)
{
    myObject = new value;
}
Bryan Menard
Depending on the type of the object, you may need to create a separate synchronization object. See http://www.albahari.com/threading/part2.aspx - you can't lock a value type.
TrueWill
+1  A: 

You can atomically update the variable without locking by using Interlocked.CompareExchange until you're successful. This avoids the overhead of locking while ensuring consistency, the following pseudo code should do it, sorry I'm not too familiar with C#.

static void atomic_add(ref int ptr, int addend){
  int previous = *ptr;
  while(1){
    int observed = Interlocked.CompareExchange(ptr, previous+addend, previous);
    if(observed == previous){
      break;
    }else{
      previous = observed;
    }
  }
}

CompareExchange will replace the value at the first argument with the second argument if the value pointed to by the first argument is equal to the third argument, and returns the value in memory at ptr when CompareExchange was called. If the value returned by compare exchange is the same as the previous value observed at ptr then the value was successfully updated and the loop breaks, otherwise, the value in the pointer changed since its last read and previous is updated and we try again.

From what I've read Interlocked.CompareExchange exists for only int32, floats, and objects (though not sure if that one would be completely lockless?). I imagine it would work for wider values on 64 bit platforms, but I have nothing to back that up.

miishuu
there is an interlocked.add as well.the technique you've described seems to be the best, coupled with thread.volatileread()locks would be overkill for a single variable.
obelix
+4  A: 

The best option is to use a ReaderWriterLockSlim (or a ReaderWriterLock if you're not using .net 3.5). Tip: This tutorial should get you started.

Darwyn
That is awesome, I was looking for something just like that!
Brandon
+1  A: 

Assuming some thread updates your shared variable, if you don't use any synchronization, then your other threads:

  • May or may not read the updated value immediately. If not, they will read it later
  • Will have an inconsistent value (some will get the new value, others will have the updated value) for a short period of time

If these issues are not significant, and if your logic doesn't depend on the value of the shared variable then no synchronization is necessary. Just allow all threads access to the shared variable.

What are you trying to achieve? It will be helpful to get a better answer.

Edit:

As ShuggyCoUk points out, use this approach with care. It relies on atomic read and writes, which depends on the type of your shared variable. Excerpt from here:

Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic.

Nader Shirazie
if the value is >32bits on some platforms he could get a torn read...
ShuggyCoUk
@shuggy: thanks for the reminder. Is the updated answer more accurate, or is it better to just avoid this in general?
Nader Shirazie
it's a valid answer, and fine so long as the variable is atomic. the problem is people not being aware of the subtlety of it. I have trouble thinking of a useful real world example that could make use of it except with a single writing thread and multiple reading threads. asignment to a reference type to switch in a new object on the fly is about the only one I can think of otherwise.
ShuggyCoUk
A: 

Use .Net types that are natively atomic
It depends what type of variable you're using. Some variables act atomically. Atomic writes means the cpu writes the entire variable in one go, or you can at least consider it as doing so. This means no other thread sees a partially updated variable - which would clearly be bad! Variables that behave atomically would behave as you ask with no locking required.

Assignments to reference types, bool, char, byte, sbyte, short, ushort, uint, int and float are atomic.

I got the list of atomic types here: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/a5a3c1b4-9f76-43d7-90a6-6572c59491fe

See section 5.5 of the C# specification here: http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/CSharp%20Language%20Specification.doc

Scott Langham
+1  A: 

I would put the data into an immutable 'class' (so it is a reference type).

If you want to update the value you first build a new instance and then update the reference to it (which is an atomic operation).

Each reader thread will get the consistent old or the consistent new value (depending of the point in time it reads from the reference). It is not possible to get intermediate results because the data class is immutable!

rstevens