Amarus
Amarus

Reputation: 137

Turn based synchronization between threads

I'm trying to find a way to synchronize multiple threads having the following conditions:

Here's a basic example of what I was thinking of doing:

// Somewhere in the code:
ManualResetEvent manualResetEvent = new ManualResetEvent(true); // Allows external call
CountdownEvent countdownEvent = new CountdownEvent(1); // Can't AddCount a CountdownEvent with CurrentCount = 0

void ExternallyCalled()
{
    manualResetEvent.WaitOne(); // Wait until CyclicCalculations is having its beauty sleep

    countdownEvent.AddCount(); // Notify CyclicCalculations that it should wait for this method call to finish before starting the next cycle

    Thread.Sleep(1000); // TODO: Replace with actual method logic

    countdownEvent.Signal(); // Notify CyclicCalculations that this call is finished
}

void CyclicCalculations()
{
    while (!stopCyclicCalculations)
    {
        manualResetEvent.Reset(); // Block all incoming calls to ExternallyCalled from this point forward

        countdownEvent.Signal(); // Dirty workaround for the issue with AddCount and CurrentCount = 0
        countdownEvent.Wait(); // Wait until all of the already executing calls to ExternallyCalled are finished

        countdownEvent.Reset(); // Reset the CountdownEvent for next cycle.

        Thread.Sleep(2000); // TODO: Replace with actual method logic

        manualResetEvent.Set(); // Unblock all threads executing ExternallyCalled

        Thread.Sleep(1000); // Inter-cycles delay
    }
}

Obviously, this doesn't work. There's no guarantee that there won't be any threads executing ExternallyCalled that are in between manualResetEvent.WaitOne(); and countdownEvent.AddCount(); at the time the main thread gets released by the CountdownEvent.

I can't figure out a simple way of doing what I'm after, and almost everything that I've found after a lengthy search is related to producer/consumer synchronization which I can't apply here.

Edit: The solution

As per the accepted answer, this is the gist of how to do what I've wanted:

// Somewhere in the code:
ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim();

void ExternallyCalled()
{
    readerWriterLockSlim.EnterReadLock();

    Thread.Sleep(1000); // TODO: Replace with actual method logic

    readerWriterLockSlim.ExitReadLock();
}

void CyclicCalculations()
{
    while (!stopCyclicCalculations)
    {
        readerWriterLockSlim.EnterWriteLock();

        Thread.Sleep(2000); // TODO: Replace with actual method logic

        readerWriterLockSlim.ExitWriteLock();

        Thread.Sleep(1000); // Inter-cycles delay
    }
}

Upvotes: 1

Views: 178

Answers (1)

Kris Vandermotten
Kris Vandermotten

Reputation: 10201

It looks like you need a ReaderWriterLockSlim. Your cyclic thread is the "writer", the other threads are "readers".

Upvotes: 4

Related Questions