First, I am aware of questions like this:
reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?
... but I am still uncertain if I can avoid using lock(){} in my case.
In my case I have a class which represents some state and only a SINGLE thread that ever modifies that state from time to time. There are many threads that read the state though.
Do I need Interlocked.Exchange() in my case on the state object? Do I absolutely have to use lock(){}
Here is my example code reduced to a bare minimum:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MultiThreadingExample
{
class State
{
    public int X { get; set; }
    public string Str { get; set; }
    public DateTime Current { get; set; }
}
class Example
{
    State state;
    CancellationTokenSource cts = new CancellationTokenSource();
    Task updater;
    List<Task> readers = new List<Task>();
    public void Run()
    {
        updater = Task.Factory.StartNew(() =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                // wait until we have a new state from some source
                Thread.Sleep(1000);
                var newState = new State() { Current = DateTime.Now, X = DateTime.Now.Millisecond, Str = DateTime.Now.ToString() };
                // critical part
                state = newState;
            }
        }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        for (int i = 0; i < 10; i++)
        {
            readers.Add(Task.Factory.StartNew(() =>
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    // critical part
                    var readState = state;
                    // use it
                    if (readState != null)
                    {
                        Console.WriteLine(readState.Current);
                        Console.WriteLine(readState.Str);
                        Console.WriteLine(readState.X);
                    }
                }
            }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default));
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        new Example().Run();
        Console.ReadKey();
    }
}
}
 
     
     
     
     
    