Craig
Craig

Reputation: 1940

Can I use a lock with this ManualResetEvent to ensure thread safety?

Say I have two functions that manipulate a count, and an OnTimer function that fires at a regular interval.

void IncrementCount()
{
    _myCount++;
}

void OverwriteCount(int newValue)
{
    _myCount = newValue;
}

void OnTimer()
{
    Console.WriteLine(_myCount);
}

My desire is that if/when OverwriteCount is called, IncrementCount can't be executed until the timer function executes.

My initial thought to resolve this was to use a ManualResetEvent to help synchronize behaviors:

private static ManualResetEventSlim mre = new ManualResetEventSlim(initialState: true);

void IncrementCount()
{
    mre.Wait(-1); // can't increment until the event is signaled
    _myCount++;
}

void OverwriteCount(int newValue)
{
    mre.Reset(); // unsignal the event, blocking threads
    _myCount = newValue;
}

void OnTimer()
{
    Console.WriteLine(_myCount);
    mre.Set(); // signal the event
}

My concern is a degenerate, multi-threaded scenario where thread A gets past the mre.Wait() in IncrementCount() but hasn't actually incremented _myCount yet. Thread B then calls mre.Reset() and overwrites _myCount. Thread A then gets a turn and increments _myCount.

Could I solve this by also adding a lock inside IncrementCount() and OverwriteCount() to ensure only one thread can modify _myCount at a time? Do I risk deadlock if I get stuck waiting on the reset event while holding the lock?

Upvotes: 0

Views: 142

Answers (1)

TheGeneral
TheGeneral

Reputation: 81503

If i understand you, then yes it would work if you chose what to lock appropriately. There is probably a more granular way to do this, but as of now i see nothing wrong with this

void IncrementCount()
{
   mre.Wait();

   // lets not cause a race, lock until OverwriteCount is finished
   lock (_sync)
   {
      _myCount++;
   }
}

void OverwriteCount(int newValue)
{
   // lock this so we can assure the count is updated
   lock (_sync)
   {
      mre.Reset(); // unsignal the event, blocking threads
      _myCount = newValue;
   }
}

void OnTimer()
{
   Console.WriteLine(_myCount);
   mre.Set(); // signal the event
}

Upvotes: 1

Related Questions