jw.*_*jw. 2 c# multithreading monitor race-condition pulse
我有一个简单的生产者/消费者场景,其中只有一个项目被生产/消费.此外,生产者在继续之前等待工作线程完成.我意识到这种情况可以避免多线程的全部问题,但请假设它真的需要这样(:
这段代码不能编译,但我希望你能得到这个想法:
// m_data is initially null
// This could be called by any number of producer threads simultaneously
void SetData(object foo)
{
lock(x) // Line A
{
assert(m_data == null);
m_data = foo;
Monitor.Pulse(x) // Line B
while(m_data != null)
Monitor.Wait(x) // Line C
}
}
// This is only ever called by a single worker thread
void UseData()
{
lock(x) // Line D
{
while(m_data == null)
Monitor.Wait(x) // Line E
// here, do something with m_data
m_data = null;
Monitor.Pulse(x) // Line F
}
}
Run Code Online (Sandbox Code Playgroud)
以下是我不确定的情况:
假设许多线程使用不同的输入调用SetData().只有其中一个进入锁内,其余的将被阻挡在A线上.假设进入锁内的那个设置m_data并进入C线.
问题:C行上的Wait()是否允许A行的另一个线程获得锁定并覆盖m_data,然后工作线程才会到达它?
假设没有发生,并且工作线程处理原始的m_data,并最终进入F行,当Pulse()关闭时会发生什么?
只有在C行等待的线程才能获得锁定吗?或者它是否会与在A线等待的所有其他线程竞争?
基本上,我想知道Pulse()/ Wait()是否特别"在引擎盖下"相互通信,或者它们是否与lock()处于同一级别.
这些问题的解决方案(如果存在的话)当然是显而易见的 - 只需用另一个锁定SetData() - 比如lock(y).我只是好奇,如果它开始是一个问题.
无法保证消费者将在另一个生产者之前排队等待或准备好的队列.维基百科上的"隐式条件监视器"下
描述了C#和Java风格的监视器.
一个很好的概述(从这个优秀的网站获取):
alt文本http://www.albahari.com/threading/waitpulse.pngMonitor
"C行上的Wait()是否允许A行的另一个线程获得锁定并覆盖m_data,然后工作线程才会到达它?"
假设SetData()由两个生产者线程P1和P2调用.
消费者线程C1也被启动.
P1,P2和C1都进入就绪队列.
P1首先获得锁定.
等待队列为空,Pulse()on line B无效.
P1等待line C,因此它被放置在等待队列中.
就绪队列中的下一个线程获取锁定.
它同样可以是P2或C1 - 在第一种情况下,断言失败.
你有竞争条件.
"假设没有发生,并且工作线程处理原始m_data,并最终进入F行,当Pulse()关闭时会发生什么?"
它会将服务员从等待队列移动到就绪队列.
锁由发出的线程持有Pulse().在脉冲线程释放锁定后,
通知的线程将有机会获得锁定(就绪队列中已经有其他人).
从MSDN,Monitor.Pulse():
"当前拥有指定对象锁定的线程调用此方法来发出锁定行的下一个线程的信号.收到脉冲后,等待线程被移动到就绪队列.当调用Pulse的线程释放锁定时,就绪队列中的下一个线程(不一定是脉冲线程)获取锁定."
"只有在C线上等待的线程才能获得锁定吗?或者它是否会与在A线上等待的所有其他线程竞争?"
就绪队列上的所有线程"竞争"下一次锁定.
如果他们直接或通过等待队列到达那里并不重要Pulse().
"队列"可以通过其他方式实现.(不是队列数据结构).
这样,Monitor实现可能无法保证公平性 - 但可能具有更高的整体吞吐量/性能.
| 归档时间: |
|
| 查看次数: |
702 次 |
| 最近记录: |