我有多个线程共享一个信号量。线程 A 持有信号量(使用锁),线程 B 和 C 正在等待同一个信号量(也使用锁)。线程共享全局变量等。
C# 中是否有一种技术可用于关闭线程 B?我可以在 A 中设置一个标志并让线程 B 检查该标志并在它控制信号量后立即退出,但我不知道有任何技术允许线程 A 将信号量交给线程 B(并获取它当线程 B 退出时返回)而不会有线程 C 夺取控制权的风险。
有人对如何解决这个设计问题有任何建议吗?如果我处理不当,我可以根据需要重写程序。
[编辑] 一位评论者指出我使用了错误的术语。评论者是正确的——我使用的是临界区,但考虑到一切都在单个进程中运行,因此在此示例中,临界区在功能上等同于更通用的术语“信号量”。
[编辑] 有人要求提供更多详细信息,所以在这里。
可以有多个线程执行代码 A。永远只有一个线程执行代码 B。
代码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)
代码 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
我怀疑我会使用 Aaron 解决方案的变体。我主要希望有更优雅的解决方案可用,但我怀疑就像这个项目的其他所有内容一样,都是蛮力和极端情况:-(。
最佳答案
我相当确定没有办法将控制权交给特定 线程,而这似乎正是您想要做的。您只能让步,期间 - 由 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
这实质上让线程 A 负责线程 C 何时开始执行。线程 A 和 B 将正常竞争,但由线程 A 向线程 C 发出事件信号。
关于c# - .NET并发问题: Can I yield a semaphore to another thread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2391190/