Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a static variable thread-safe

I have this static class which contains a static variable (a simple int). I've implemented a lock() in the Run() method of the threads, so no other threads can access to this class concurrently, but the variable still goes crazy, displaying duplicates, insanely high values, etc.

This is the class:

public static class ExplorationManager
{
    public static int Counter = 0;

    public static void ExplorerMaker(List<int[]> validPaths, List<string> myParents, string[,] myExplorationMap, List<int[]> myPositions)
    {
        foreach (var thread in validPaths.Select
        (path => new Explorer(myParents, path, myExplorationMap, myPositions)).
        Select(explorer => new Thread(explorer.Explore)))
            {
                thread.Name = "Thread of " + Counter + " generation";
                Counter++; 
                thread.Start();
    }
}

}

Is there a way to make this variable "more" thread-safe?

like image 923
Jean Carlos Suárez Marranzini Avatar asked Oct 19 '12 19:10

Jean Carlos Suárez Marranzini


People also ask

Does static variables are thread safe?

Static variables are not thread safe. Instance variables do not require thread synchronization unless shared among threads. But, static variables are always shared by all the threads in the process. Hence, access to static variable is not thread safe.

How do I make a static object thread safe in Java?

Thread Safe Singleton in JavaDeclare a private static instance of the same class. Provide a public static method that will return the singleton class instance variable. If the variable is not initialized then initialize it or else simply return the instance variable.

Can we use static variable in multithreading?

Static variable is a shared resource, which can be used to exchange some information among different threads. And we need to be careful while accessing such a shared resource. Hence, we need to make sure that the access to static variables in multi-threaded environment is synchronized.

Are static variables thread safe Swift?

Static variables in swift are not thread-safe by default.


2 Answers

There are at least 2 problems that you need to address in order to increase the safety of this type.

The first one is to make Counter private. In it's current form the variable is 100% public and it can be mutated by any piece of code in the application. Today it may be safe but there's nothing protecting you from making a mistake tomorrow. If you still want other pieces of code to be able to read the property then use an accessor

private static int m_counter;
public static int Counter {
  get { return m_counter; }
}

The second problem is that ++ isn't a safe operation on a location that is shared amongst threads. It expands out to the following code

Counter = Counter + 1;

Which is in reality doing

  1. load Counter
  2. load 1
  3. add
  4. store Counter

A thread can be interrupted an virtually any time. If one thread is interrupted at step 1, 2 or 3 and another thread fully executes the sequence then you will end up adding / storing stale values. This is why ++ is unsafe. The safe way to increment a shared value amongst threads is to use Interlocked.Increment. It's designed exactly for this purpose

Interlocked.Increment(ref m_counter);
like image 106
JaredPar Avatar answered Nov 02 '22 10:11

JaredPar


You need to use lock around all reads/writes of your static variable. Something like:

public static readonly object CounterLock = new object();

...
lock ( CounterLock )
{
    Counter++;
}
...

The point is that all reads / writes must be protected by the lock - it's not enough to protect a single place because then threads doing reads or writes may still make a change when a lock elsewhere is in effect.

A lock protects a region of code, not a variable, that's why you need a lock everywhere where you access a shared variable.

Note that you cannot lock on your Counter variable - you need an instance of a reference type as a lock, not a value type. This is why I used object as the lock type (the other answer did the same).

like image 22
xxbbcc Avatar answered Nov 02 '22 10:11

xxbbcc