Question

Sorry for the title, I couldn't find better to explain my issue...

I'm having a hard time trying to synchronize different threads in my application. It's probably an easy problem for someone that has a new look on the issue, but after hours of investigations about a deadlock, my head is exploding and I can't find a good and safe way to write my synchronization mechanism :(

Basically, I have a .Net process that runs in multiple threads (everything in a single process, so no need for IPC). I have 4 threads:

  • 1 thread, say it is called SpecificThread. There is a System.Timers.Timer that periodically executes some code.
  • 3 other threads, each running a service that executes some code periodically (while (true) loop + Thread.Sleep(few ms)).

All 3 services must run concurrently. I guarantee their concurrent execution is thread safe. The fourth thread, SpecificThread, must execute its code periodically, but it must block the execution of the 3 other services.

So basically I have SpecificThread that executes code periodically. When SpecificThread wants to execute its code periodically, it must wait for other services to complete their task. When all other 3 services completed their task, it must execute its SpecificCode while other 3 services are blocked. When its SpecificCode is executed, other 3 services can run their code again.

I have a shared instance of a SynchronizationContext object that is shared between all 4 threads. I can use it to synchronize my threads:

public class SynchronizationContext
{
    public void StartService1()
    {
        ...
    }   
    public void StopService1()
    {
        ...
    }
    ...

    public void StartSpecificCode()
    {
        // Some sync here that wait until all 3 services completed their
        // respective tasks
    }
    public void NotifySpecificCodeCompleted()
    {
        // Some sync here that allows services 1 to 3 to execute again
    }
}

The 3 services execution mechanism looks like:

// Only exits the loop when stopping the whole .Net process
while (myService.IsRunning)
{
    try
    {
        this.synchronizationContext.StartService1();

        // Do some job
    }
    finally
    {
        this.synchronizationContext.EndService1();

        // Avoids too much CPU usage for nothing in the loop
        Thread.Sleep(50);
    }
}

The SpecificThread execution mechanism:

// System.Timers.Timer that is instantiated on process start
if (this.timer != null)
{
    this.timer.Stop();
}

try
{
    // Must blocks until computation is possible
    this.synchronizationContext.StartSpecificCode();

    // Some job here that must execute while other 3
    // services are waiting
}
finally
{
    // Notify computation is done
    this.synchronizationContext.NotifySpecificCodeCompleted();

    // Starts timer again
    if (this.timer != null)
    {
        this.timer.Start();
    }
}

I can't figure out how to use critical sections as only SpecificThread must run while other are waiting. I didn't found a way with Semaphore nor AutoResetEvent (their usage introduced a hard-to-debug deadlock in my code). I'm running out of ideas here... Maybe Interlocked static methods would help?

Last word: my code must run with .Net 3.5, I can't use any TPL nor CountdownEvent classes...

Any help is appreciated!

Was it helpful?

Solution

ReaderWriterLockSlim sounds like exactly the tool that will help you the most. Have each of the services take out a read lock inside the body of their loop:

while (true)
{
    try
    {
        lockObject.EnterReadLock();

        //Do stuff
    }
    finally
    {
        lockObject.ExitReadLock();
    }
}

Then your fourth thread can enter a write lock when it wants to do it's work. The way reader/writer locks work is that any number of readers can hold a lock, as long as no writers hold the lock, and there can only be one writer holding the lock at a time. This means that none of the three workers will block other workers, but the workers will bock if the fourth thread is running, which is exactly what you want.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top