3
\$\begingroup\$

I have a .net core razor app that has a special use case where I need to have a global counter that will be incremented by every request, and yet it should remain thread-safe.

Also at web application load, this counter will be read from a database using entity framework.

I don't think that static variables are threadsafe for this scenario (since it can be read by a request then be modified after another request read its previous value).

So I was wondering if a locking mechanism is needed, or should a concurrent dictionary with a Lazy<T> be used?

public static void PrintValueLazy(string valueToPrint)
{
var valueFound = _lazyDictionary.GetOrAdd("key",
            x => new Lazy<string>(
                () =>
                    {
                        Interlocked.Increment(ref _runCount);
                        Thread.Sleep(100);
                        return valueToPrint;
                    }));
Console.WriteLine(valueFound.Value);
}
\$\endgroup\$
1
\$\begingroup\$

Since you use Interlocked.Increment(ref _runCount) than the operation is thread-safe if the value is already initialized.

Interlocked is a class designed just for the case when you need to share primitive type value between threads. Regarding to .NET Framework documentation: "Interlocked Class provides atomic operations for variables that are shared by multiple threads." See the documentation for more details.

You can also see a similar question without ConcurentDictionary aspect on Stack Overflow: C# variable thread safety.

Lazy initialization and ConcurrentDictionary are used here for the scenario when two concurrent threads try to initialize value, however, they both see that the value is not initialized, so they both start to read from a database and initialize the new value.

With lazy initialization in ConcurrentDictionary when concurrent Thread B completes the invocation after Thread A, it discards the value it has created and uses (increments) the value that Thread A already created.

Your code is exactly the same as this one where you can find a more detailed explanation of your code including steps why each part of your code is important.

So, if your question is whether the value _runCount is thread-safe in your code snippet and whether is it the right solution, the short answer is: Yes, it is and all parts of the code are important for your described use case.

\$\endgroup\$
1
  • \$\begingroup\$ this was just an example, am not sure if its the right thing to use \$\endgroup\$
    – NullKuhl
    Apr 24 '20 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.