gpt4 book ai didi

c# - 线程安全共享对象过期和重新初始化

转载 作者:太空宇宙 更新时间:2023-11-03 11:51:17 26 4
gpt4 key购买 nike

我有一些只读数据,我想初始化它们,然后以线程安全的方式定期重新初始化。对于初始化,我引入了 Joe Duffy 的 LazyInit and LazyInitOnceOnly structs as detailed in his blog ,它使用双重检查锁定模式。因此,我当前的 getter 实现简单地围绕着他的 LazyInitOnly.Value 属性,并为超时检查提供了额外的空间:

所以代码如下:

public class MyData {
public DateTime TimeStamp { get; set; }
//actual shared data ommitted

public MyData() { TimeStamp = DateTime.Now; }
}

public SharedDataContainer
{
//data to be initialised thread-safe, and shared.
//assume delegate passed on construction simply 'new's the object,
private LazyInitOnceOnly<MyData> _sharedDataInit;
//receives the result from the _sharedDataInit.Value property
private MyData _sharedData;
//time-out and reinitialise after 24 hours
private TimeSpan _timeOut = new TimeSpan(24,0,0);

public MyData SharedData
{
get{
//slight adaptation of the use of the LazyInitOnceOnly struct -
//because we want to replace _sharedData later after an expiry time out.
if(_sharedData == null)
_sharedData = _sharedDataInit.Value;
//need best ideas for this bit:
if((DateTime.Now - _sharedData.TimeStamp) > _timeOut)
{
ReInitialise();
}
return _sharedData;
}
}
}

当数据被识别为过时时,应该返回旧数据,但是应该在单独的线程上准备新数据并在准备好时换入 - 以免阻塞调用者。数据的所有后续读取都应返回旧值,直到它被更新。

所以我考虑在 ReInitialise() 方法中像这样对新线程进行排队:

() => {
//assume constructor pulls in all the data and sets timestamp
_sharedData = new MyData();
}

线程中的 _sharedData 覆盖将自动发生,所以这很好。但是使用此代码,在重建完成之前,所有后续读取都将尝试并触发线程重建 - 因为它们正在读取旧的 _sharedData 的 TimeStamp 属性。

确保只触发一次重建的最佳方法是什么?

最佳答案

或者,(再次不使用 LazyInit 东西)在构造函数中设置 Int32 m_buildState = 0。将 m_publishData 成员(在这种方法中,这是您的自定义数据对象类型,而不是 LazyInit 对象类型)设置为 null。

在 getter 中,设置 d = Interlocked.CompareExchange(ref m_buildState, 1, 0)。这里 d 是局部决策变量。

如果d==2 查看是否发生了数据更新超时;如果是这样,接下来测试是否 Interlocked.CompareExchange(ref m_buildState, 3, 2)==2。如果是这样,启动一个后台线程来重建数据。返回 m_publishData。 (后台重建线程的最后一步必须先更新m_publishData,然后再将m_buildState设置为2。)

如果 d==3 返回 m_publishData 成员。

如果 d==1 等待 d>=2。要以最佳方式执行此操作,请等待事件发生(如果要优化代码,您可以先旋转等待/测试 d>=2 一点)。然后返回 m_publishData。

如果 d==0,在当前线程上重建,然后将 m_publishData 设置为数据对象,然后将 m_buildState 设置为 2,然后发出事件信号。

我在这里假设重建线程重建所花费的时间不足以进行另一次重建,并且不需要并发操作超时。如果这些假设不安全,则需要进行更多检查。

关于c# - 线程安全共享对象过期和重新初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2085999/

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