I have multiple threads that share use of a semaphore. Thread A holds the semaphore (using lock) and threads B and C are waiting on that same semaphore (also using lock). The threads share global variables, etc.
Is there a technique in C# that I can use to shut down thread B? I can set a flag in A and have thread B check that flag and exit as soon as it gets control of the semaphore, but I don’t know of any technique to allow thread A to yield the semaphore to thread B (and get it back when thread B exits) without the risk of thread C seizing control.
Anyone have any suggestions how to address this design problem? I can rewrite the program as necessary if I am approaching this incorrectly.
[Edit]
A commenter has pointed out that I am using the wrong terminology. The commenter is correct – I am using a critical section, but given that everything is running in a single process, in this example critical sections are functionally equivalent to the more general term ‘semaphore’.
[Edit]
Someone asked for more details, so here it is.
There can be multiple threads executing Code A. There’s only ever 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 a variant of Aaron’s solution will be what I use. I was mostly hoping there was somewhat more elegant solution was available, but I suspect that like everything else about this project, it’s all brute force and corner cases :-(.
I’m fairly certain that there’s no way to yield control to a specific thread, which seems to be what you’re trying to do. You can only yield, period – it’s up to the Windows scheduler to decide what thread gets to run next.
The situation is that you have three threads, A, B, and C. A has the lock, B and C are waiting for it, and you want a way to guarantee that B gets to executed next.
The obvious solution is to use more than one lock and/or sync primitive. You can combine the semantics of
lockwith aManualResetEvent. Make thread C wait for both the event and the critical section, but thread B only has to wait for the critical section. Under normal circumstances, you signal the event just before releasing the lock, which leaves it up to the OS to decide which thread to execute. In the special case, you don’t signal the event at all, leaving thread B to execute while C is still blocked.Once B is done, then you signal the event to let C finish.
An (untested) example would be:
This essentially puts Thread A in charge of when Thread C gets to execute. Threads A and B will compete normally but it’s up to Thread A to signal the event for Thread C.