Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在对象内的函数调用期间,是否可以删除缓存中的对象?_C#_Caching_Thread Safety - Fatal编程技术网

C# 在对象内的函数调用期间,是否可以删除缓存中的对象?

C# 在对象内的函数调用期间,是否可以删除缓存中的对象?,c#,caching,thread-safety,C#,Caching,Thread Safety,鉴于代码: private static readonly object GetMyObjLock = new object(); public static MyObject GetFromCache() { var key = "MyObj"; var cache = HttpContext.Current.Cache; if (cache[key] == null) { lock (GetMyObjLock) {

鉴于代码:

private static readonly object GetMyObjLock = new object();
public static MyObject GetFromCache()
{
    var key = "MyObj";
    var cache = HttpContext.Current.Cache;
    if (cache[key] == null)
    {
        lock (GetMyObjLock)
        {
            if (cache[key] == null)
            {
                cache.Add(key,
                    new MyObject(), null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);
            }
        }   
    }
    return (MyObject) cache[key];
}
电话:

var myObj = GetFromCache();
myObj.PerformMethod();
在另一个线程上侦听某些代码时:

if(message == "invalidate")
{
    Httpcontext.Current.Cache.Remove("MyObj");
}
两个问题:

  • PerformMethod
    是否始终完成
  • GetFromCache()
    方法和
    PerformMethod
    调用之间是否有机会使
    myObj
    等于
    null

考虑线程的这种定时:

线程1:

var myObj = GetFromCache();
public static MyObject GetFromCache()
{
    var key = "MyObj";
    var cache = HttpContext.Current.Cache;
    if (cache[key] == null)
    {
        lock (GetMyObjLock)
        {
            if (cache[key] == null)
            {
                cache.Add(key,
                    new MyObject(), null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);
            }
        }   
    }
    return (MyObject) cache[key];
}
myObj.PerformMethod();
线程2:

if(message == "invalidate")
{
    Httpcontext.Current.Cache.Remove("MyObj");
}
线程1:

var myObj = GetFromCache();
public static MyObject GetFromCache()
{
    var key = "MyObj";
    var cache = HttpContext.Current.Cache;
    if (cache[key] == null)
    {
        lock (GetMyObjLock)
        {
            if (cache[key] == null)
            {
                cache.Add(key,
                    new MyObject(), null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);
            }
        }   
    }
    return (MyObject) cache[key];
}
myObj.PerformMethod();
它会破坏你的实现

一种可能的修复方法是将
新MyObject()
存储在局部变量中,然后将其添加到缓存中,然后返回局部变量。这将起作用,因为它是一个强有力的参考:

var myobject = new MyObject();
cache.Add(key,
myobject, null,
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
CacheItemPriority.Normal, null);
return myobject;

考虑线程的这种定时:

线程1:

var myObj = GetFromCache();
public static MyObject GetFromCache()
{
    var key = "MyObj";
    var cache = HttpContext.Current.Cache;
    if (cache[key] == null)
    {
        lock (GetMyObjLock)
        {
            if (cache[key] == null)
            {
                cache.Add(key,
                    new MyObject(), null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);
            }
        }   
    }
    return (MyObject) cache[key];
}
myObj.PerformMethod();
线程2:

if(message == "invalidate")
{
    Httpcontext.Current.Cache.Remove("MyObj");
}
线程1:

var myObj = GetFromCache();
public static MyObject GetFromCache()
{
    var key = "MyObj";
    var cache = HttpContext.Current.Cache;
    if (cache[key] == null)
    {
        lock (GetMyObjLock)
        {
            if (cache[key] == null)
            {
                cache.Add(key,
                    new MyObject(), null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);
            }
        }   
    }
    return (MyObject) cache[key];
}
myObj.PerformMethod();
它会破坏你的实现

一种可能的修复方法是将
新MyObject()
存储在局部变量中,然后将其添加到缓存中,然后返回局部变量。这将起作用,因为它是一个强有力的参考:

var myobject = new MyObject();
cache.Add(key,
myobject, null,
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
CacheItemPriority.Normal, null);
return myobject;

修复它的方法是使用
Add
函数的输出查看您添加的项是否实际添加到缓存中,如果它已经存在,它将返回上一个实例,如果它不存在,它将返回
null
。当它返回null时,您只需将传入的对象设置为第二个参数,作为从函数返回的结果

private static readonly object GetMyObjLock = new object();
public static MyObject GetFromCache()
{
    var key = "MyObj";
    var cache = HttpContext.Current.Cache;
    MyObject result;

    //Try to pull from the cache.
    result = (MyObject)cache[key];
    if(result == null)
    {
        //This lock is used to make sure the MyObject constructor is not called 
        // concurrently, it is not for thread safe access to the cache.
        lock(GetMyObjLock)
        {
            //Check to see if anyone made a new object while we where waiting.
            result = (MyObject)cache[key];
            if(result == null)
            {
                var newObject = new MyObject();

                //Try to add to cache, if the object was already added by someone who 
                // does not use the GetMyObjLock this function returns the previously 
                // added instance.
                result = (MyObject)cache.Add(key,
                    newObject, null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);

                //If result is null then we successfully added a new 
                // item, assign it to result.
                if(result == null)
                    result = newObject;
                }
            }
        }
    }        
    return result;
}

修复它的方法是使用
Add
函数的输出查看您添加的项是否实际添加到缓存中,如果它已经存在,它将返回上一个实例,如果它不存在,它将返回
null
。当它返回null时,您只需将传入的对象设置为第二个参数,作为从函数返回的结果

private static readonly object GetMyObjLock = new object();
public static MyObject GetFromCache()
{
    var key = "MyObj";
    var cache = HttpContext.Current.Cache;
    MyObject result;

    //Try to pull from the cache.
    result = (MyObject)cache[key];
    if(result == null)
    {
        //This lock is used to make sure the MyObject constructor is not called 
        // concurrently, it is not for thread safe access to the cache.
        lock(GetMyObjLock)
        {
            //Check to see if anyone made a new object while we where waiting.
            result = (MyObject)cache[key];
            if(result == null)
            {
                var newObject = new MyObject();

                //Try to add to cache, if the object was already added by someone who 
                // does not use the GetMyObjLock this function returns the previously 
                // added instance.
                result = (MyObject)cache.Add(key,
                    newObject, null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);

                //If result is null then we successfully added a new 
                // item, assign it to result.
                if(result == null)
                    result = newObject;
                }
            }
        }
    }        
    return result;
}

你所说的“PerformMethod将永远完成”是什么意思?你甚至没有给我们看这个方法的代码。我们怎么知道呢?@rory.ap我的意思是,如果在调用过程中侦听器将其从缓存中删除,那么它是否保证完成。它会抛出异常(例如“此对象不再存在”),还是会完成并删除它?从缓存中删除对象不会“销毁”它。它只是有资格进行垃圾收集。这不会发生,myObj参考文件确保了这一点。您似乎确实忘记锁定另一个线程,希望您没有。您所说的“将始终完成PerformMethod”是什么意思?你甚至没有给我们看这个方法的代码。我们怎么知道呢?@rory.ap我的意思是,如果在调用过程中侦听器将其从缓存中删除,那么它是否保证完成。它会抛出异常(例如“此对象不再存在”),还是会完成并删除它?从缓存中删除对象不会“销毁”它。它只是有资格进行垃圾收集。这不会发生,myObj参考文件确保了这一点。您似乎确实忘记了锁定另一个线程,希望您没有。了解缓存是线程安全的,但是假设
MyObject
构造函数很昂贵(比如它从数据库中提取数据),我们只想调用它一次。在这种情况下,锁定有意义吗?@TomGullen在这种情况下,是的,它有意义。还有,看看我更新的答案,我把它改了一点,你根本不需要循环。我将再次更新答案以使用锁。谢谢,这非常有帮助!理解缓存是线程安全的,但是假设
MyObject
构造函数很昂贵(比如它从数据库中提取数据),我们只想调用它一次。在这种情况下,锁定有意义吗?@TomGullen在这种情况下,是的,它有意义。还有,看看我更新的答案,我把它改了一点,你根本不需要循环。我将再次更新答案以使用锁。谢谢,这非常有帮助!您应该检查
cache.Add
的结果,如果它返回非空值,则传入的
myobject
未添加到缓存中。
Add
函数的作用更像是一个
GetOrAdd
函数,除非它在成功添加时返回
null
。@ScottChamberlain:如果每个用户都考虑
锁(GetMyObjLock)
,那么这应该不是必需的,您应该检查
缓存的结果。Add
,如果返回非空值,则传入的
myobject
未添加到缓存中。
Add
函数的作用更像是一个
GetOrAdd
,除非它在成功添加时返回
null
。@ScottChamberlain:如果每个用户都考虑了
锁(GetMyObjLock)
,那么这应该不是必需的