【发布时间】:2019-06-13 15:09:55
【问题描述】:
这是一个基于this question 的单独问题。回顾一下,假设我有两个操作计数的函数和一个定期触发的 OnTimer 函数。我的愿望是,如果/当调用 OverwriteCount 时,在计时器函数执行之前不能执行 IncrementCount。
建议的解决方案是:
private int _myCount = 0;
private readonly object _sync = new object();
private ManualResetEventSlim mre = new ManualResetEventSlim(initialState: true);
void IncrementCount()
{
mre.Wait(); // all threads wait until the event is signaled
lock (_sync)
{
_myCount++;
}
}
void OverwriteCount(int newValue)
{
lock (_sync)
{
mre.Reset(); // unsignal the event, blocking threads
_myCount = newValue;
}
}
void OnTimer()
{
lock (_sync)
{
Console.WriteLine(_myCount);
mre.Set(); // signal the event
}
}
ManualResetEventSlim 尝试确保一旦 OverwriteCount() 取消事件信号,对 _myCount 的任何修改都必须等到 OnTimer() 执行。
问题:
- 假设线程 A 进入 IncrementCount() 并通过事件的 wait() - ManualResetEvent 的初始状态已经发出信号。
- 然后线程 B 启动并执行所有 OverwriteCount()。
- 然后线程 A 继续获取锁并递增 _myCount。
这违反了我的目标,因为在 OnTimer 运行之前调用 OverwriteCount() 后 _myCount 会发生变化。
Rejected Alternative:我可以在 lock(_sync) 中移动 mre.Wait(),但这会带来死锁风险。如果线程 A 调用 IncrementCount() 并在等待时阻塞,则没有其他线程可以获取锁来释放它。
问题:我是否需要不同的同步原语来实现我的目标?或者,我对线程安全问题是否有误?
【问题讨论】:
-
您可以在
IncrementCount的锁内再次检查,0-等待只是检查信号状态,如果不正确则退出。 IE。在 IncrementCount 的 lock 语句中添加这个:if (!mre.Wait(0)) return;.
标签: c# .net multithreading concurrency