views:

358

answers:

2

Can someone explain why examples on threading will always make an object (specifically a member variable) static if it is to be accessed by multiple threads?

My issue is that making the member variable static means that it will be shared among all other instantiations of the class. Sometimes I find that I would like multiple threads within a class "touch" the member variable but at the same time allow every object to have their own copy.

Would the answer to performing what I mentioned simply be replacing:

  • Using volatile keyword
  • Using lock(object)
+5  A: 

There is nothing that requires member variables to be static for threading.

Most examples use a static variable, specifically because they're trying to show how to synchronize data between two separate threads. If you wish to do this, you need to have a value that's accessible by both threads. Static variables are the simplest option, since they're accessible everywhere.

You could just as easily pass a reference to a class into your thread, and have that thread and your main thread share a non-static member variable. You will need to provide a good locking/synchronization mechanism, however, since you'll have two threads sharing one instance of a class.

Reed Copsey
Should the keyword volatile be included with static?Aren't there concerns with caching the static value in one thread and not getting the most recent in the other thread?
Setheron
@Setheron: always use `lock(object)` to access variables shared by multiple threads. This will give you exclusive access and it does everything for you so all threads always get the most recent values (memory barrier).
dtb
See my answer for the use of volatile. In most practical cases, you can completely ignore it ever exists. (Although a volatile guru can probably make a splendid case for volatile, IMHO, you're not going to need it.)
Ruben
+2  A: 

If you want each thread to use the same member variable, but also maintain a separate copy, you've got a contradiction here. Either they use the same variable or they don't. Unless I'm not understanding you right.

Having said that, if you really need a static field to be accessed by multiple threads, each maintaining their own, private value, you can use the ThreadStatic attribute. This attribute ensures that the static field will be private to each thread ("thread local" as it's usually called).

[ThreadStatic]
private static bool s_threadHasDoneItsWork;

Note that you cannot initialize a thread local static field through a static constructor or directly as static type field = value. (The compiler won't complain, but it won't work properly.)


volatile tells the runtime that the field (static or not) must always be accessed directly from your main memory, so you don't need to use locks or memory barriers to synchronize threads and cores. It's always up-to-date, so to speak, whereas other fields can still be waiting for your processor's memory cache to sync up with your main memory.

But that's exactly the limit of what it does: only access to that particular field. As soon as you've read it, the value is stale again, so don't ever think of doing something like volatileField++ (which means "read volatileField, add one to the value you've just read, set volatileField", and not "increment volatileField", you'll need to use the Interlocked class for that, which is a lot more expensive).

A safe way to use volatile fields is reading them directly, but when you're modifying them, to use a locking mechanism before you either read or write them. (The only reasonable exception I can think of is a boolean flag like "I'm done now".)

The practical use of volatile fields is, not surprisingly, rather limited. Stick with simple locking; the lock keyword, and the corresponding Monitor class's methods take care of both the single user and memory synchronization (as soon as you enter and exit the lock).

Ruben
Yea I saw the Threadstatic attribute on the MSDN and it confused the hell out of me. It seems to go against the definition of a static variable if it every thread maintains their own personal copy.
Setheron
It does in a way, yes. But it can be useful if you need to maintain thread-specific state, or state that methods that are called from one of your methods need to be able to access, but no-one else. Depending on its use, thread local storage can prevent the need for thread synchronization (as there is no sharing between threads), so it can be useful.
Ruben
doesn't even make sense why it would need the static field then.Threadstatic alone should then make sense.
Setheron
No, ThreadStatic is only possible on static fields. That's a CLR limitation though. It's a lot more involved if you need to implement thread local storage at the instance level, because you can never predict how many instances there will be, and when they will be created and garbage collected. With static fields you do know: just one, right now, and only cleaned up when the thread dies.
Ruben
I see what you mean.Although I would've assumed VolatileField++ to be an atomic instruction that would be thread safe if the field is atomic.
Setheron
An atomic update is quite expensive (as you'd need to sync not only memory, but the flow analysis and branch predictions your average processor can make these days might have to be undone as well, since they could have been based on the wrong assumptions). That's not something you'd want a frequent operator like ++ to do. So you'll have to explicitly tell the framework to do this expensive operation through Interlocked.Increment(ref volatileField).
Ruben