3

I read some articles and did some testings/investigating and I think there's NOT accurate conculsion (due to incorrect wording maybe )

Ok . few investigations :

There was this guy who asked this question :

Why are static fields generally considered threadsafe?

Well , all of the repliers said : No. they are not.

Eric also said :

You have it backwards.Because static fields and methods are likely to be accessed from multiple threads, it is a good programming practice to do the work to ensure that they are threadsafe.

(this is pretty close to my claim which i'll ask here later)

But I also found here that Hans said :

enter image description here

And oh boy — this other guy said :

Re-entrancy is still a problem, though. static is not thread-safe, and even static readonly is not re-entrant-safe.

Ok , i'm confused.

p.s. I'm not talking about this kind of situation :

public class A
 {
  public static List<int> LST = new List<int>();
 }

List<> is not thread safe so I don't care who holds it. BUT ->

Let's look at this

public class A
 {
  public static int Five=5;
 }

What is not thread safe about this code ?

I can't see how Five could not always be 5 :

enter image description here

As far as I know - Five could never be 0( initial value) and it would always be five no matter how many threads are accessing it !

NOW , I DO AGREE that If I was writing a code which USES this Five field , then I'd have to watch out for changed value !

Example :

if (Five < array.Length) return array[five]; //can throw an IndexOutOfBoundsException if five is modified

With this - I Agree !

But (imho) it is incorrect to say ( as a rule) that static fields are not thread safe !

Their usage has to be treated as if it could change via another thread.

(Also, obviously - Static fields which reference a non-threadsafe object like List<> - surely not going to be thread safe)

What i'm trying to say here is that static fields are not thread safe for specific scenarios , and not as a rule !

Question :

  • Can someone please shed light ? I'm sure I miss something here ( or am I not ? ) is it true that static fields are not always non-thread safe ( as a rule)

  • And what about this readonly which makes static field threadsafe (all it does it make it one time initialize without reassigned ) ? does it make it thread safe or does it not ? (and what about re-entrent ?)

Community
  • 1
  • 1
Royi Namir
  • 144,742
  • 138
  • 468
  • 792

6 Answers6

2

A static variable, doesn't mean it's "constant", it just means that it was statically allocated at compile time, rather than dynamically at run-time.

If you set the static variable before starting any threads, and then never, ever, change it again, but only read from it, then, by the nature of the logic in your code, you are never putting yourself in a situation in which you will be exposed to the problems associated with non-thread safe code. That is not the same as saying that static variables are thread safe.

Pre-emptive threading is called that because a thread switch can cause code execution to pre-empt the execution of another thread, even in mid-write, or mid-read. In other words, consider that your static variable is an integer, which depending on the architecture, could be 4 bytes, or 8 bytes. Unless the variable is specifically declared atomic, one thread could start reading the memory, but say it only manages to read the first 2 bytes before another thread pre-empts it and writes to the same variable. When the first thread resumes, it reads the remaining bytes, which of course, by now, is inconsistent.

2
public class A
{
  public static int Five=5;
}

This example is not thread-safe in the sense that if two threads execute return ++Five;, both threads might end up returning 6, instead of returning 6 and then 7. There's a race condition.

That's why Hans says read-only fields are inherently thread-safe (kinda). What he forgot to mention is that the field's type should also be immutable (which int is). A field that can only be read, and never changed in any way, is thread-safe.

What i'm trying to say here is that static fields are not thread safe for specific scenarios , and not as a rule !

Yes, being static has nothing to do with thread-safety. Thread-safety depends on:

  • Whether a variable is shared across different threads.
  • Whether that variable can be mutated.
  • Whether those mutations are atomic.
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • Yes I know that's why we need to use `Interlock.Increment` but does the statement as a piece of code is atomic ? `public static int Five=5;` ? and what about this `public static int Five= new MyStruct()`; – Royi Namir May 22 '14 at 08:20
  • p.s. this is exactly what i said :-) _Their **usage has to be treated** as if it could change via another thread._ – Royi Namir May 22 '14 at 08:23
  • @RoyiNamir I'm not sure I fully understand your question, but: The declaration of the field alone isn't enough to decide whether that field is thread-safe. You have to consider how the shared state could possibly be manipulated. If you encapsulate the field `Five` in such a way that it can only be mutated atomically, then yes, it'll be thread-safe. – dcastro May 22 '14 at 08:27
  • This is exactly the clarification i was needed. it's all about usage of the static field. Reagarding my comment question : does this statement is thread safe ? `public static int Five= 5;` ? which means all thread would see the same value / always ? – Royi Namir May 22 '14 at 08:28
  • @RoyiNamir If you're talking about the initialization bit (`=5` and `= new MyStruct()`), then, as far as I'm aware, I don't think a thread would ever see `Five` set to its default value, `0`, before it has been initialized. – dcastro May 22 '14 at 08:31
  • ACK - _If you're talking about the initialization_ , — Yes I was talking about this. – Royi Namir May 22 '14 at 08:32
  • @RoyiNamir Quick addendum: I'm pretty sure no thread would ever see the static field set to its default value, but I *think* there's a chance that the struct's constructor might be called twice. So, if the constructor happens to have side-effects, there would be a race condition. – dcastro May 22 '14 at 09:43
1

It does make it threadsafe - but that is a feature of readonly, not static. Variables that can not change value are per definition not something that can have a change in one thread while read in another thread, by the virtue of.... missing the change to start with.

Generally anything that is read only is per definition thread safe. It is only with changes in values that you start getting into trouble.

TomTom
  • 61,059
  • 10
  • 88
  • 148
  • Tnx - you're talking about the 20% question (`readonly`) and I thank you for that. What about the 80% question which is about the statement that it is not correct to say that static fields are not always non-threadsafe ? :-) ( my `five` example ^^) - can you shed a light pls ? – Royi Namir May 22 '14 at 08:08
1

Readyonly static fields can only be initialized at either declare time or in the static constructor and not afterwards. So, they can't be changed by none other that the static constructor which is called only once when first static field or method of that class is accessed. Static fields (not readonly) are not threadsafe on their own because multiple threads can still access them and change them to produce race conditions.

If you are not changing any state in a class, then there is no question of making it thread safe. Thread safety is done to make modifying the fields avoid race conditions and keep their value consistent across the threads.

Please run below example in Console to check the output to see the field five is not Thread-safe.

public class CheckThreadSafety
{
    private static int five = 5;

    public static void Increment(int iVal)
    {
        five += iVal;
    }

    public static int CurrentFiveValue { get { return five; } }
}

public class Program
{
    public static void Main()
    {
        for (var i=0; i<10000; i++)
        {   var t = i;
            Task.Factory.StartNew ( () =>
            {   
                CheckThreadSafety.Increment(t);
                Console.WriteLine("Five Value should be : " + (t + 5).ToString() + ", and is: " + CheckThreadSafety.CurrentFiveValue);
            } );
        }
    }
}

Moreover, if you change five field in above code to be public, then callers have to ensure it's thread-safety.

Another example using Singleton, Read more here:

-Below code is not thread-safe:

using System;

public class Singleton
{
   private static Singleton instance;

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }
}

-But, below code due to readonly is thread-safe:

public sealed class Singleton
{       
    private static readonly Singleton instance = new Singleton();

    private Singleton() { }

    public static Singleton Instance
    {
        get 
        {
            return instance; 
        }
    }
}
S2S2
  • 8,322
  • 5
  • 37
  • 65
  • this is exactly what i said :-) _Their **usage has to be treated** as if it could changed via another thread_ . but this code ` private static int five = 5;` IS thread safe. it's just that we need to be careful with OPERATIONS over the static field. – Royi Namir May 22 '14 at 08:26
  • @RoyiNamir, Yes, if you do not want any static methods to accidentally modify static field five, you can also make it readonly or const. Generally, static methods should not modify static fields because static fields are shared by all instances, but if you do, make them thread-safe.. – S2S2 May 22 '14 at 08:28
  • `Increment(i)` ?? wont compile and I think ref is needed – Royi Namir May 22 '14 at 08:35
  • I have fixed compile problems and made it more accurate test. – Royi Namir May 22 '14 at 08:41
1

is it true that static fields are not always non-thread safe?

static shouldn't be in the argument itself. static has nothing to do with thread safety. It just allows the field to be the part of "Type" itself rather than "Instance".

what about this readonly which makes static field threadsafe ? does it make it thread safe or does it not ?

Answer depends on what do you meant by thread safe? Thread safe is more general term in which everybody has their own meaning, If you can be more precise in what do you mean by thread safe, It will be easy to answer.

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
1
  1. Fields larger than 32 bits (at least on a 32-bit system) cannot even be accessed atomically.
  2. Fields (even non static), compared to properties, don't provide any mechanism to control their access.

So the question is, do you really need to expose your code to all the potential problems? Having a public static field in your app makes it temptingly simply to change it from an arbitrary piece of code and create threading problems.

Or, you can decide that all callers must take a lock before working with the field, where the lock object is also a public static field. So, you are delegating the thread-safety concern to the callers of that class, and relying on nothing more than conventions to keep your code safe. Why, when there are better ways to achieve it? What about deadlocks?

As you've said yourself:

Their usage has to be treated as if it could change via another thread.

It am pretty sure this implies that you are actually aware they are inherently not thread safe.

vgru
  • 49,838
  • 16
  • 120
  • 201