21

So we've all seen the Threading notification on MSDN for many available generic objects:

"Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe."

My question is, what is it about being an instance variable vs a public static makes it unsafe?

cyberconte
  • 2,371
  • 4
  • 21
  • 27
  • 4
    The part in brackets is what causes confusion when reading - rather read it as: Public static *members* of this type are thread safe. This means that the static members of this object Type are threadsafe, it's not referring to a "public static Type;" instance being declared in your code. – David d C e Freitas Dec 01 '10 at 07:09

5 Answers5

17

This is only true in general.

In general static methods are static because they are not dependant on nor do they access any instance defined data that another thread could also access. In general, the only variables they (a static method) utilizes are variables declared and tied to the static memory of the class the method is implemented in, not to the memory allocated for object -(the instance of the class) created for that object. A static method does not and cannot reference or utilize any such variable. If a method uses this kind of instance data variable, tied to a specific instance, it cannot be static. An Instance method, in contrast, does access some data element (property or field) of the instance.

If, otoh, a static method accesses a static property or field of the class, it is equally non-thread -safe.

There are four conditions needed for a race to be possible.

  1. The first condition is that there are memory locations that are accessible from more than one thread. Typically, these locations are global/static variables or are heap memory reachable from global/static variables.
  2. The second condition is that there is a property (often called an invariant), which is associated with these shared memory locations that must be true, or valid, for the program to function correctly. Typically, the property needs to hold true before an update occurs for the update to be correct.
  3. The third condition is that the invariant property does not hold during some part of the actual update. (It is transiently invalid or false during some portion of the processing).
  4. The fourth and final condition that must occur for a race to happen is that another thread accesses the memory while the invariant is broken, thereby causing inconsistent or incorrect behavior.
Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
14

Nothing inbuilt makes static any more-or-less different (re thread-safety) than instance, except:

  • static methods are often stateless "pure functional" methods, making them automatically thread-safe
  • there is a clear expectation on static members to be thread-safe (since you can't really control what each thread is doing at once) - so it is expected that any static method that could risk thread-safety be made thread-safe

This is not true for instance methods:

  • instance methods commonly access state on that instance
  • there is no expectation of thread safety unless it is made explicit in the documentation

So in general it is expected that the caller manage thread-safety over instances.

There are exceptions where instances are thread-safe (usually for things that are deeply tied to threading, such as a producer-consumer queue) - but IMO any static member that isn't thread safe is a bug.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    @marc, I humbly disagree... not to say that such does not exist, but I have never had an expectation that static methods are thread-safe, nor have I heard of such an expectation. Static methods can still access static variables, (from any class), as well as instance variables in objects passed in as method parameters. – Charles Bretana Aug 16 '09 at 01:48
  • (cont) The only way your expectation could be relied upon is if all static methods were prohibited from using any passed in by-reference variables, or instances of reference types, and from accessing any static variables in that or any other class. This would seem to be an extraordinarily onerous restriction, just to allow your "expectation" to be reliable. – Charles Bretana Aug 16 '09 at 01:49
  • You reasoning doesn't follow. I am talking about its own static state (such as a static dictionary/list on a static field, used by the static method), since that cannot be controlled by the caller. Normally static methods are thread-safe by the simple trick of not using any private state ;-p The state of things like `ref` or ref-type args *is* controlled by the caller, and should be managed as such. It likewise doesn't impact external calls. The expectation **is** there, otherwise you would have a **lot** of locking in almost every line of your C# code. – Marc Gravell Aug 16 '09 at 08:07
  • @marc, It is the use of shared public state that makes a block of code potentially unsafe, not private state. Any private local variables are by definition only accessible by the stack frame (thread) that created them. So, clearly, I must not be understanding what you mean by public/private... In any event, if a static method is passed a variable containing state, then it is potentially not thread safe, as another thread can call that static method while a previous thread is "in progress" with some invariant in a transient invalid state. Only local (to the method) variables are safe – Charles Bretana Aug 17 '09 at 16:05
  • I mean private to the implementation, not local to the method; for example, a (private) static dictionary that underpins a static method (perhaps as a cache) must be synchronized. – Marc Gravell Aug 17 '09 at 17:43
  • @marc, Yes, in yr private static dictionary example, I agree, it must be synchronized. but, again, anything that is not stored in the methods stack frame, whether public, private, instance based or static, is generally susceptible to, (can create) a race condition, and, (if the other race conditons (see my answer) are possible), must be synchronized. But I still don't understand what you mean by "private to the implementation". – Charles Bretana Aug 19 '09 at 02:49
  • @Marc, as, obviously, anything declared as static must be scoped at the level of a type (class/struct), it is accessible from any thread. but any variable declared at the level of a type (class/struct) that is instance based is also accessible from any thread that has a reference to that instance, whether it is a public or private variable... – Charles Bretana Aug 19 '09 at 02:52
  • Yes, and that gets entirely back to my point; there isn't the same expectation of safety around *instance* state. If you have an instance available to multiple threads, you *expect* (unless told otherwise) to have to synchronize access yourself before calling methods. With static methods, the default position is reversed, and you *don't* expect to have to manually synchronize access to a static method. Some instances (typically closely tied to threading) are thread-safe, but they are the minority. – Marc Gravell Aug 19 '09 at 06:54
  • Why is the expectation different, when as we seem to agree, the static method, (and whatever state it manipulates), is equally accesible to multiple threads,. and therefore just as potentially unsafe? It is the shared menory, and the existence, and nature of the invariant which depends on that memory, that should be the determinent, not whether the method is instance-based or static. – Charles Bretana Aug 19 '09 at 11:10
  • 1
    Static state is **by definition** available to all threads (except for `[ThreadStatic]`). Instances are *generally* localised to one thread. I wouldn't expect instances of "average class Jo" to be thread-safe, for all sorts of reasons involving performance, sheer unnecessary code, untested threading code (which is just as dangerous as non-existant synchronization). Threading and synchrnoization needs to happen *carefully*, but only on those classes that will be realistically impacted. – Marc Gravell Aug 19 '09 at 12:06
  • But rather than going around in circles; what would you propose? Should "class Person { public string Name {get;set;}}" be made fully synchronized? Where does it end? Better to handle instance synchronization separately (or side-step with immutability). – Marc Gravell Aug 19 '09 at 12:08
  • Hey Mark, btw immutable instances are always thread safe, right? – Joan Venge Aug 19 '09 at 16:45
  • @marc, When you say that "instances are generally localized to one thread", what is this based on? is this statement not dependant on how a client uses the instance? As well as where and how client code passes arounf reference(s) to that instance? – Charles Bretana Aug 23 '09 at 00:20
  • Oh absolutely; but **most of the time** an object is only really accessed by one thread. When you have multiple threads accessing the same object then it gets fun and you have to start synchronizing - but the vast majority of .NET code does *not* have this problem to deal with. Hence the *generally* (note italics). – Marc Gravell Aug 23 '09 at 06:39
8

It's the issue of state. What general makes methods unsafe for multiple threads is they do not access shared state in a thread safe manner. Static methods in general do not access shared state and hence are less likely to run into this problem. It's still possible to have race conditions in static / shared methods if they touch static data but in general static methods do not.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
0

The problem with methods that are not thread safe is concurrent access to shared resources such as instance variables. If a static method only works on private/local data, it is inherently thread safe. However, there is no guarantee that static methods do that - this must be done explicitly.

Thus for a static method to be thread safe it cannot access static members without using synchronization and it should copy whatever data it receives as input before modifying it.

Brian Rasmussen
  • 114,645
  • 34
  • 221
  • 317
  • I am not talking about private as in private members of the type, but private as in local. Because each thread has its own stack where locales are stored these are not shared among different threads and are thus inherently thread safe. – Brian Rasmussen Aug 09 '09 at 10:07
0

TLDR; "Does this mean static methods are inherently thread safe? The answer is no. Classes with the above note will have thread safe static methods because the Microsoft engineers wrote the code in a thread safe manner, perhaps by using locks or other thread synchronization mechanisms" (quote taken from http://odetocode.com/Articles/314.aspx)

More detail

What is it? Nothing, except the code written for that particular class.

The statement is a declaration telling you that the programmers who wrote the class have made sure that all of the static members (methods and properties) are thread safe (but have not done so for instance members).

The have made sure statics are thread safe because, being static, it is very likely that they will be called by multiple threads, so they put in the extra work necessary to make sure this will be okay. Often static methods are also stateless functions, meaning they are already generally thread safe (no additional work needed).

In contrast, for instance members the statement is simply them telling you they have not been as careful with them.

Often instances will be created by a single thread and only accessed by that thread; if the instance is never accessed by multiple threads, then thread safety is not an issue, so the programmers didn't bother to add it.

The statement is not a claim about any inherent properties of static vs instance; both can be unsafe unless you put specific code in to ensure multiple threads can access them without problems (or if by nature they are already thread safe, e.g. a stateless function).

It is simply a statement that the programmers who wrote those classes have made sure that the static members are safe, but have not done so for instance members.

Sly Gryphon
  • 3,751
  • 1
  • 25
  • 17