我在一个名为 Loadeable 的类中有一个锁定对象:
private readonly object _lock;
lock(_lock){ /*...*/ }
语句仅在可加载类中使用,以防止死锁。 (注意:_lock对象的访问者是私有的)
由于我仍想从外部运行锁定代码,我将以下方法添加到可加载类:
public void RunLockedProcedure(Action Procedure) {
lock(_lock) {
Procedure();
}
}
可加载还包含一个名为IsLoaded
的属性和一个名为Load(int)
的方法,但我没有展示它们,因为它是很多代码而且并不重要。但请务必注意IsLoaded
和Load(int)
访问线程安全数据。
现在想象一下名为Item and Creation 的 Loadable的子类。
整数_creationId
和以下方法是项:
public Creation LazyGetCreation() {
int creationIdCopy = 0;
//The following lambda provides thread-safety inside this instance.
RunLockedProcedure(() => {
if(!IsLoaded) {
throw new InvalidOperationException("A component cannot be loaded if the instance is not loaded");
} else {
if(_creationId < 1)
throw new InvalidOperationException("The loaded Id of the creation component (" + _creationId + ") is less than 1.");
creationIdCopy = _creationId;
if(Creation == null)
Creation = new Creation();
}
});
//We are not in a thread-safe block and thus Creation might already be null again (I had to use the elvis operator)
Creation?.RunLockedProcedure(() => {
if(!Creation.IsLoaded)
Creation.Load(creationIdCopy); //This is a heavy operation and takes a bit time...
});
}
让我现在解决问题:
elvis运算符很棒,但是对Creation(?).RunLockedProcedure(() => { /*...*/ })
的调用应该真正在上面的线程安全块中执行(它需要加载 Item )。
但后来我遇到的问题是,非常重的Creation.Load(creationIdCopy)
也会在锁定的块中执行,从而锁定项一段时间。我正在寻找的是一种安全调用Creation.RunLockedProcedure(/*...*/)
但在非锁定范围内执行() => { /*...*/ }
的方法。 (必须锁定到Creation实例,但不能锁定到Item实例)
也许有一个我还不知道的功能,但找到解决方案会很糟糕。
非常感谢你。
答案 0 :(得分:0)
线程安全保证应该在Load
本身处理,而不是在外部处理。否则,您需要在每个调用load的地方使用它。这样的事可能适合你:
private object _lock = new object();
public void Load(int someID)
{
if (IsLoaded) //No-locked check, early exit.
return;
lock (_lock) //We think it's not loaded, lock to prevent issues and double check
if (IsLoaded)
return;
else
IsLoaded = true; //Immediately set IsLoaded = true
try
{
//Do loading stuff
} catch (Exception ex) {
lock(_lock)
IsLoaded = false; //We failed to load, set back to false again
throw;
}
}
然后你这样称呼它:
public Creation LazyGetCreation() {
int creationIdCopy = 0;
//The following lambda provides thread-safety inside this instance.
RunLockedProcedure(() => {
if(!IsLoaded) {
throw new InvalidOperationException("A component cannot be loaded if the instance is not loaded");
} else {
if(_creationId < 1)
throw new InvalidOperationException("The loaded Id of the creation component (" + _creationId + ") is less than 1.");
creationIdCopy = _creationId;
if(Creation == null)
Creation = new Creation();
}
});
Creation.Load(creationIdCopy);
}
如果您不想立即设置IsLoaded
,则可以在创建对象之前引入IsLoading
并检查两者是否为false,并立即将IsLoading
设置为true。 / p>