0

I have a method StartProcess(). I want this method to throw an exception if the same method is called by another thread at the same time or by the same initial thread before EndProcess() is called.

I tried the Monitor class but I wasn't sure how to apply it to the above stated case. What I saw that was close to what I was looking for was:

var obj = new Object();

// Define the critical section.
Monitor.Enter(obj);
try {
   // Code to execute one thread at a time.
}
// catch blocks go here.
finally {
   Monitor.Exit(obj);
}

I need guidance to handle my exact stated scenario. I've been trying all day but couldn't get it to work.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Kacey Ezerioha
  • 1,068
  • 4
  • 22
  • 46
  • 1
    Why would you want to do this? Anyone calling the method would need to use their own synchronization mechanism to prevent hitting the exception you're explicitly throwing, which would mean you're synchronizing twice. If you're going to have this operation handle its own synchronization, it should have an expected behavior to do if the lock is taken, whether that's to wait (synchronously or asynchronously), skip the section, etc. – Servy Jul 05 '21 at 19:39
  • @Servy Let's assume the method should handle it's synchronization, how can I achieve this in code? – Kacey Ezerioha Jul 05 '21 at 19:46
  • 1
    If the method should handle its own synchronization then it shouldn't throw if called by multiple threads at the same time, as you've just defined it as not an exceptional situation, but rather one that's supported. – Servy Jul 05 '21 at 20:00
  • `obj` should be a field in order to lock afaics. – lidqy Jul 05 '21 at 22:10

2 Answers2

1

You need a synchronization mechanism that disallows reentrancy, and the Monitor is not one of them (it is reentrant by design). My suggestion is to use a SemaphoreSlim, which is not reentrant. This mechanism doesn't look to see which thread is calling it. It's just a simple counter. In order to acquire the semaphore if it's available, or return instantly if it's not available, you can invoke the Wait method with a zero millisecondsTimeout, like this:

SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
bool acquired = semaphore.Wait(0);
if (!acquired) throw new InvalidOperationException();
try
{
    // Code to execute disallowing concurrency
}
finally
{
    semaphore.Release();
}
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
0

It seems you are looking for the ManualResetEventSlim:

ManualResetEventSlim resetEvent = new ManualResetEventSlim();

// Block other calls.
resetEvent.Wait();

// Reset state to block next calls.
resetEvent.Reset();

try
{
  // Your code
}
finally
{
  // Set state to allow next call to proceed.
  resetEvent.Set();
}
Philipp Ape
  • 519
  • 3
  • 13