Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
813 views
in Technique[技术] by (71.8m points)

c# - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...