gpt4 book ai didi

c# - ManualResetEvent 未始终如一地释放所有等待线程的问题

转载 作者:行者123 更新时间:2023-11-30 17:11:00 26 4
gpt4 key购买 nike

我正在尝试实现一个类,该类使用一个简单的缓存来保存从内部服务检索到的数据。我正在使用 ManualResetEvent 来阻止多个线程,这些线程可能会尝试与第一个线程同时刷新缓存数据,以便在通过调用 Set() 和 Reset() 检索数据后成功向其他线程发出信号继续进行。在测试时,我注意到有时所有线程都被释放,有时 1 个或多个线程没有被释放并超时,几乎就像我在所有线程被释放之前调用 Reset 一样。有人可以解释我做错了什么吗?

我在下面包含了代码的简化版本。

    private bool _updating;
private const int WaitTimeout = 20000;
private DateTime _lastRefresh;
private object _cacheData;
private readonly ManualResetEvent _signaller = new ManualResetEvent(false);

private void RefreshCachedData()
{
Console.WriteLine("ThreadId {0}: Refreshing Cache", Thread.CurrentThread.ManagedThreadId);
if (_updating)
{
Console.WriteLine("ThreadId {0}: Cache Refresh in progress, waiting on signal.", Thread.CurrentThread.ManagedThreadId);

// another thread is currently updating the cache so wait for a signal to continue
if (!_signaller.WaitOne(WaitTimeout))
Console.WriteLine("ThreadId {0}: Thread timed out ({1}s) waiting for a signal that the cache had been refreshed",
Thread.CurrentThread.ManagedThreadId,WaitTimeout);

Console.WriteLine("ThreadId {0}: Signal recieved to use refreshed cache.", Thread.CurrentThread.ManagedThreadId);
}
else
{
try
{
_updating = true;

var result = _requestHandler.GetNewData();

if (!result.Success)
{
Console.WriteLine("Failed to retrieve new data.");
}
else
{
// switch the cache with the new data
_cacheData = result.Data;

Console.WriteLine(
"ThreadId {0}: Cache refresh success.",
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(8000);
}
}
catch (Exception ex)
{
Console.WriteLine("Error occured: {0}", ex);
}
finally
{
// Set the refresh date time regardless of whether we succeded or not
_lastRefresh = DateTime.Now;
_updating = false;

// signal any other threads to to carry on and use the refreshed cache
Console.WriteLine("ThreadId {0}: Signalling other threads that cache is refreshed.", Thread.CurrentThread.ManagedThreadId);
_signaller.Set();
_signaller.Reset();
}
}
}

最佳答案

看起来您的线程在重置之前没有从 ResetEvent 中释放。

您可以通过创建打开的事件并让第一个线程进入您的方法来重置它来解决问题。

或者,您可以通过执行以下操作来避免 ManualResetEvent 行为的变幻莫测:

private object _latch = new object();
private bool _updating;

private void UpdateIfRequired()
{
lock (_latch)
{
if (_updating)
{
//wait here and short circuit out when the work is done
while (_updating)
Monitor.Wait(_latch);

return;
}

_updating = true;
}

//do lots of expensive work here

lock (_latch)
{
_updating = false;
Monitor.PulseAll(_latch); //let the other threads go
}
}

查看此页面以获得有关其工作原理的精彩解释 http://www.albahari.com/threading/part4.aspx#_Signaling_with_Wait_and_Pulse

关于c# - ManualResetEvent 未始终如一地释放所有等待线程的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11646590/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com