我正在阅读 MSDN 上的 AutoResetEvent 文档,随后的警告有点让我困扰......
“重要: 不能保证每次调用 Set 方法都会释放一个线程。如果两次调用距离太近,以至于第二次调用发生在一个线程被释放之前,则只释放一个线程。就好像第二个电话没有发生一样。此外,如果在没有线程等待且 AutoResetEvent 已发出信号时调用 Set,则调用无效。”
但是这个警告基本上扼杀了拥有这种线程同步技术的真正原因。例如,我有一个将保留工作的列表。而且只有一个生产商会在列表中添加工作。我有消费者(不止一个),正在等待从列表中获得工作……类似这样的事情……
制作人:
void AddJob(Job j)
{
lock(qLock)
{
jobQ.Enqueue(j);
}
newJobEvent.Set(); // newJobEvent is AutoResetEvent
}
消费者
void Run()
{
while(canRun)
{
newJobEvent.WaitOne();
IJob job = null;
lock(qLock)
{
job = jobQ.Dequeue();
}
// process job
}
}
如果上述警告为真,那么如果我很快将两个作业加入队列,那么只有一个线程会获取该作业,不是吗?我假设 Set 将是原子的,即它执行以下操作:
- 设置事件
- 如果线程正在等待,选择一个线程唤醒
- 重置事件
- 运行选定的线程。
所以我基本上对 MSDN 中的警告感到困惑。这是一个有效的警告吗?
最佳答案
即使警告不是真的并且 Set 是原子的,你为什么要在这里使用 AutoResetEvent?假设您有一些生产者连续排队 3 个事件,并且有一个消费者。处理完第二个作业后,消费者会阻塞并且永远不会处理第三个作业。
我会使用 ReaderWriterLockSlim对于这种类型的同步。基本上,您需要多个生产者才能拥有写锁,但您不希望消费者在生产者仅读取队列大小时长时间锁定生产者。
关于c# - AutoResetEvent - 两次快速调用不能保证线程释放 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9493680/