这是否使用Monitor.Wait的/脉冲有一个竞争条件?
-
26-09-2019 - |
题
我有一个简单生产者/消费者情形,其中仅存在曾经正在生产中的单个项目/消耗。此外,制片人,然后再继续等待工作者线程结束。我知道那种避免了多线程的整点,但请你只认为它真正需要的是这样的(:
此代码不能编译,但我希望你的想法:
// 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
}
}
这里的情况,我不知道:
假设许多线程调用的SetData()与不同的输入。 只有其中一人将获得锁内,其余的将被封锁(A线) 假设一个锁套的 M_DATA 强>内得到并使得其对C线的方式。
问题:无法对C线的等待()允许在A线另一个线程来获得锁和重写的 M_DATA 强>前的工作线程甚至到达它
?假设不会发生,且工作线程处理原始的 M_DATA ,并最终使得其方式线f,当脉冲()熄灭发生了什么?
只能在C线线程等待能够获得锁?还是会与所有其他线程A线的等待也可以竞争?
基本上,我想知道如果脉冲()/等待()相互专门“发动机罩下”进行通信,或者如果他们是在与锁相同的水平()。
到这些问题的解决,如果它们存在,是显而易见的当然 - 只是环绕的SetData()与另一个锁定 - 比如,锁(Y)。 我只是好奇,如果它甚至开始有问题。
解决方案
有没有保证,消费者将之前另一位制片人等待或就绪队列排队。结果
C#和Java风格监视器上维基百科描述的,“隐式状态监视器” 一个下>点击
在Monitor
会发生什么很好的概述(摘自此优秀的网站):
“可以在C线的等待()允许在A线另一个线程以获得工作线程甚至到达之前锁定和重写M_DATA?”
假设SetData()
由两个生产者线程,的 P1 强>&的 P2 强>叫。结果
消费者螺纹,的 C1 强>开始为好。结果,
的 P1 强>,<强> P2 和<强> C1 所有进入就绪队列。结果
的 P1 强>首先获取锁。结果
等待队列为空,在Pulse()
line B
没有效果。结果
的 P1上line C
强>等待,因此它被放置在等待队列。结果
在就绪队列中的下一个线程获取锁。结果
它同样可以是的 P2 强>或 C1 强> - 在第一种情况下,则断言失败结果。
你有一个竞争条件。
“假设不会发生,且工作线程处理原始M_DATA,并最终使其以线f方式,当脉冲()熄灭,会发生什么?”
它将从等待队列就绪队列移动服务员。结果
该锁由线程认为问题Pulse()
。结果
该通知线程的有机会的脉动线程释放后获取锁锁(有可能已经是别人就绪队列)。结果
从 MSDN,监视器.Pulse():点击
“当前拥有指定的对象的锁的线程调用此方法,以信号通知所述下一个线程在线路的锁。在接收到脉冲,等待线程移动到就绪队列,当线程调用的脉冲释放锁,在就绪队列中的下一个线程(其不一定是呈脉冲式的线程)获取锁“。
“只会线程等待C线能够获得锁?还是会与所有其他线程A线的等待也可以竞争?”
所有线程都在具有下一个锁的就绪队列“竞争”。结果,
不要紧,如果他们到达那里的直链或从等待队列通过Pulse()
的手段。
<子>的“队列”可能被通过其它手段来实现。 (不是队列数据结构本身)。结果
这样一Monitor
实现可能无法保证公平性 - 但可能具有更高的总体生产能力/性能。 子>