Call Action every X cycles I want to call an Action every X cycles (in my case, to a transaction commit every 100 records), so I do:

public class CyclicActionCaller
{
    private int _counter;
    private int _cycleValue;
    private Action _methodToCall;

    public CyclicActionCaller()
    {
        _counter = 0;            
    }

    public CyclicActionCaller Every(int cycleValue)
    {
        _cycleValue = cycleValue;
        return this;
    }

    public CyclicActionCaller Call(Action methodToCall)
    {
        _methodToCall = methodToCall;
        return this;
    }

    public void PerformCall()
    {
        Interlocked.Increment(ref _counter);
        // IS THIS THREAD SAFE - SHOULD BE CALLED EVERY _counter % _cycleValue - EVEN IN MULTITHREADING ENVIRONMENT
        if (_counter % _cycleValue == 0)
        {
            _methodToCall();                
        }
    }
}

CyclicActionCaller cyclicActionCaller = new CyclicActionCaller();
using (ModelContainer container = new ModelContainer())
{
   cyclicActionCaller.Every(100).Call(() =&gt; { container.SaveChanges(); });

   while(...) { // Import Loop - assume multiple workers inside
       cyclicActionCaller.PerformCall(); // every worker calls this after inserting a row
   }
}


Is this function thread safe? I want that - even if multiple threads call PerformCall - that it is just called once every 100 calls.
No, it's not thread-safe. Between the call to Interlocked.Increment() and the if check, another thread could call Interlocked.Increment(). That means both of them could see that _counter is 101, which means a call to _methodToCall would be skipped.

But this is exactly why Interlocked.Increment() returns the incremented value. So the thread-safe version would be:

public void PerformCall()
{
    if (Interlocked.Increment(ref _counter) % _cycleValue == 0)
        _methodToCall();                
}


This is exactly why writing code like this is hard (although this is a simple situation, so it's not that hard here). It's much easier to write correct multi-threaded code, if you lock all shared values.

Also, if you do something like this, you need to be sure that inserting a row in your code is also thread-safe. And the same applies to SaveChanges(). For example, if you used something like ConcurrentQueue in a straightforward way, it would be possible for SaveChanges() to save more than 100 items at a time, because new items could have been inserted between the call to Interlocked.Increment() and the final dequeue from the queue. This may not be a problem for you, but you should think about that.