.NET Concurrency Question: can I provide a semaphore to another thread

I have several threads that use the use of semaphore. Thread A holds the semaphore (using locks), and threads B and C wait for the same semaphore (also using locks). Streams are shared by global variables, etc.

Is there a way in C # that I can use to close thread B? I can set the flag to and have thread B check this flag and exit as soon as it takes control of the semaphore, but I don’t know any technique for thread A to give semaphore to thread B (and get it back when thread B ends ), without risking to control the capture of thread C.

Anyone have any suggestions to solve this design problem? I can rewrite the program as necessary if I approach it incorrectly.

[Edit] One commenter indicated that I am using the wrong terminology. The comment is correct: I use a critical section, but given that everything works in one process, in this example the critical sections are functionally equivalent to the more general term "semaphore".

[Edit] Someone asked for details, so here it is.

There are several threads executing code A. There is only one thread executing code B.

Code A:

private static Thread workerThread = null;

lock (lockObject)
{
    ... do some work ...

    if (...condition...)
    {
        if (workerThread != null)
        {
            // Kill the worker thread and continue only after it is dead.
            quitWorkerThread = true;
            // Wait for the thread to die.
            while (workerThread.IsAlive)
            {
                Thread.Sleep(50);
            }
            workerThread = null;
            quitWorkerThread = false;
        } // if (workerThread != null)
    } // if (...condition...)

    ... do some more work ...

    if (...condition...)
    {
        if (workerThread == null)
        {
            // Start the worker thread.
            workerThread = new Thread(WorkerThread);
            workerThread.Start();
        } // if (workerThread == null)
    } // if (...condition...)

    ... do even more work ...

} // lock (lockObject)

Code B:

private void WorkerThread()
{
    while (true)
    {
        if (quitWorkerThread)
        {
            return;
        }

        Thread.Sleep (2000);

        if (quitWorkerThread)
        {
            return;
        }

        lock(lockObject)
        {
            if (quitWorkerThread)
            {
                return;
            }
            ... do some work ...
        } // lock(lockObject)
    } // while (true)
} // WorkerThread

I suspect that the Aaron solution option will be what I use. I mostly hoped that there was a slightly more elegant solution, but I suspect that, like everything else in this project, all these are brute forces and corner cases: - (.

+3
source share
4 answers

, , , , , . , - Windows, , .

, : A, B C. A , B C , , , B .

/ . lock ManualResetEvent. C , , B . , , , , . , B , C .

B , , C .


():

// Main thread is Thread A
object myLock = new Object();
AutoResetEvent myEvent = new AutoResetEvent(false);
ManualResetEvent completedEvent = new ManualResetEvent(false);

ThreadPool.QueueUserWorkItem(s =>
{
    for (int i = 0; i < 10000; i++)
    {
        lock (myLock)
        {
            // Do some work
        }
    }
    completedEvent.Set();
});  // Thread B

ThreadPool.QueueUserWorkItem(s =>
{
    for (int i = 0; i < 10000; i++)
    {
        myEvent.WaitOne();
        lock (myLock)
        {
            // Do some work
        }
    }
});  // Thread C

// Main loop for thread A
while (true)
{
    lock (myLock)
    {
        // Do some work
        if (SomeSpecialCondition)
            break;
        else
            myEvent.Set();
    }
}

completedEvent.WaitOne(); // Wait for B to finish processing
if (SomeSpecialCondition) // If we terminated without signaling C...
    myEvent.Set();        // Now allow thread C to clean up

Thread A, Thread C. A B , Thread A, Thread C.

+4

Monitor.Pulse, , , .

, . , ReaderWriterLockSlim.

, scenerio .NET .

+1

( : - , @Aaronaught ManualResetEvents, , .)

: , .

, , , , C , B , , B , C , :

    object lockObject = new object();
    int WaitCounter = 0;

    void B()
    {
        System.Threading.Interlocked.Increment(ref WaitCounter);

        try
        {
            lock (lockObject)
            {
            }
        }
        finally
        {
            System.Threading.Interlocked.Decrement(ref WaitCounter);
        }
    }

    void C()
    {
        while (true)
        {
            // always attempt to yield to other threads first
            System.Threading.Thread.Sleep(0);
            lock (lockObject)
            {
                if (WaitCounter > 0)
                    continue;

                // ...

                return;
            }
        }
    }

, , concurrency .:)

+1

Aaronaught , , .

Basically, you transfer control between threads and threads, deciding whether it is time for them to work or not. If this is not the case, they simply PulseAll (move all existing waiting threads to the waiting queue) and Wait to (pulsate, and then) again get the lock. At some point, he decided that ThreadC was good to go.

public class ThreadsGettinCrazy {
  static readonly _sync = new object();
  static bool _threadCReady = false;

  public void ThreadA() {
    while (true) {
      lock(_sync) {
        while(/* my condition not met */) {
          Monitor.PulseAll(_sync);
          Monitor.Wait(_sync);
        }
        // do work, possibly set _threadCReady = true
        Monitor.PulseAll(_sync);
      }
      if (/* i'm done */) break;
    }
  }

  public void ThreadB() {
    while (true) {
      lock(_sync) {
        while(/* my condition not met */) {
          Monitor.PulseAll(_sync);
          Monitor.Wait(_sync);
        }
        // do work, possibly set _threadCReady = true
        Monitor.PulseAll(_sync);
      }
      if (/* i'm done */) break;
    }
  }

  public void ThreadC() {
    lock(_sync) {
      while (!_threadCReady) {
        Monitor.PulseAll(_sync);
        Monitor.Wait(_sync);
      }
      // do work
    }
  }
}
+1
source

Source: https://habr.com/ru/post/1735688/


All Articles