Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.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# 如何使用静态列表<;T>;作为缓存对象?_C#_Design Patterns_Collections_Synchronization - Fatal编程技术网

C# 如何使用静态列表<;T>;作为缓存对象?

C# 如何使用静态列表<;T>;作为缓存对象?,c#,design-patterns,collections,synchronization,C#,Design Patterns,Collections,Synchronization,我有一个静态的列表作为一个缓存对象,它被多个线程大量读取。我需要从数据库中每隔5分钟刷新一次对象 问题是,如果我在某个线程使用对象时更新该对象,foreach循环将抛出异常 我曾尝试实现像inUse=true和inUpdate=true这样的标志,以及等待标志设置或释放的while循环,但最终它变得太麻烦了,我认为存在一个bug,根本无法更新对象 对于这样的案例,我可以使用类似于设计模式的东西吗 编辑: 基于,我能够生成以下代码: using System; using System.Coll

我有一个静态的
列表
作为一个缓存对象,它被多个线程大量读取。我需要从数据库中每隔5分钟刷新一次对象

问题是,如果我在某个线程使用对象时更新该对象,
foreach
循环将抛出异常

我曾尝试实现像
inUse=true
inUpdate=true
这样的标志,以及等待标志设置或释放的while循环,但最终它变得太麻烦了,我认为存在一个bug,根本无法更新对象

对于这样的案例,我可以使用类似于设计模式的东西吗


编辑:

基于,我能够生成以下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication4 
{
    class Program 
    {
        static Timer g;
        static Timer f;
        static Timer r;
        static Timer l;

        static void Main(string[] args) 
        {
            f=new Timer(
                o => SetK(new Random().Next(Int32.MinValue, Int32.MaxValue)), 
                null, 0, 1);

            l=new Timer(
                o => SetK(new Random().Next(Int32.MinValue, Int32.MaxValue)), 
                null, 1, 1);

            g=new Timer(o => RunLoop(), null, 1000, Timeout.Infinite);
            r=new Timer(o => RunLoop(), null, 1001, Timeout.Infinite);

            Console.ReadLine();
        }

        public static void SetK(int g) 
        {
            try {
                if(g<0) {
                    List<int> k=new List<int>(10);

                    k.Insert(0, g);
                    k.Insert(1, g);
                    k.Insert(2, g);
                    k.Insert(3, g);
                    k.Insert(4, g);
                    k.Insert(5, g);
                    k.Insert(6, g);
                    k.Insert(7, g);
                    k.Insert(8, g);
                    k.Insert(9, g);

                    SynchronizedCache<Int32>.Set(k);
                }
                else {
                    List<int> k=new List<int>(5);
                    k.Insert(0, g);
                    k.Insert(1, g);
                    k.Insert(2, g);
                    k.Insert(3, g);
                    k.Insert(4, g);

                    SynchronizedCache<Int32>.Set(k);
                }
            }
            catch(Exception e) {
            }
        }

        public static void RunLoop() 
        {
            try {
                while(true) {
                    try {
                        SynchronizedCache<Int32>.GetLock().EnterReadLock();

                        foreach(var g in SynchronizedCache<Int32>.Get()) {
                            Console.Clear();
                            Console.WriteLine(g);
                        }
                    }
                    finally {
                        SynchronizedCache<Int32>.GetLock().ExitReadLock();
                    }
                }
            }
            catch(Exception e) {
            }
        }
    }

    public static class SynchronizedCache<T> 
    {
        private static ReaderWriterLockSlim 
            cacheLock=new ReaderWriterLockSlim();

        private static List<T> cache=new List<T>();

        public static ReaderWriterLockSlim GetLock() 
        {
            return cacheLock;
        }

        public static void Set(List<T> list) 
        {
            cacheLock.EnterWriteLock();

            try {
                cache=list;
            }
            finally {
                cacheLock.ExitWriteLock();
            }
        }

        public static List<T> Get() 
        {
            return cache;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统线程;
命名空间控制台应用程序4
{
班级计划
{
静态定时器g;
静态定时器f;
静态定时器r;
静态定时器l;
静态void Main(字符串[]参数)
{
f=新定时器(
o=>SetK(new Random().Next(Int32.MinValue,Int32.MaxValue)),
null,0,1);
l=新定时器(
o=>SetK(new Random().Next(Int32.MinValue,Int32.MaxValue)),
空,1,1);
g=新计时器(o=>RunLoop(),null,1000,Timeout.Infinite);
r=新计时器(o=>RunLoop(),null,1001,Timeout.Infinite);
Console.ReadLine();
}
公共静态无效设置(int g)
{
试一试{

if(g使用命名空间中的一个并发集合

System.Collections.Concurrent
命名空间提供了多个线程安全的集合类,当多个线程同时访问集合时,这些类应替代
System.Collections
System.Collections.Generic
命名空间中的相应类型


不幸的是,没有一个
系统.Collections.Concurrent
集合可以很好地映射到
列表
。如果我需要这样的东西,我会使用一个包装器,在内部使用
ReaderWriterLockSlim
来保护它。例如:

public class ConcurrentList<T>: IList<T>
{
    private readonly List<T> _theList;
    private readonly ReaderWriterLockSlim _rwlock = new ReaderWriterLockSlim();

    public ConcurrentList()
    {
        _theList = new List<T>();
    }

    public ConcurrentList(IEnumerable<T> collection)
    {
        _theList = new List<T>(collection);
    }

    public ConcurrentList(int size)
    {
        _theList = new List<T>(size);
    }

    public int IndexOf(T item)
    {
        _rwlock.EnterReadLock();
        try
        {
            return _theList.IndexOf(item);
        }
        finally
        {
            _rwlock.ExitReadLock();
        }
    }

    public void Insert(int index, T item)
    {
        _rwlock.EnterWriteLock();
        try
        {
            _theList.Insert(index, item);
        }
        finally
        {
            _rwlock.ExitWriteLock();
        }
    }

    public T this[int index]
    {
        get
        {
            _rwlock.EnterReadLock();
            try
            {
                return _theList[index];
            }
            finally
            {
                _rwlock.ExitReadLock();
            }
        }
        set
        {
            _rwlock.EnterWriteLock();
            try
            {
                _theList[index] = value;
            }
            finally
            {
                _rwlock.ExitWriteLock();
            }
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        _rwlock.EnterReadLock();
        try
        {
            foreach (var item in _theList)
            {
                yield return item;
            }
        }
        finally
        {
            _rwlock.ExitReadLock();
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    // other methods not implemented, for brevity
}
公共类ConcurrentList:IList
{
私有只读列表_theList;
私有只读ReaderWriterLockSlim _rBlock=new ReaderWriterLockSlim();
公共ConcurrentList()
{
_列表=新列表();
}
公共ConcurrentList(IEnumerable集合)
{
_列表=新列表(集合);
}
公共ConcurrentList(整数大小)
{
_列表=新列表(大小);
}
公共整数索引(T项)
{
_rwlock.EnterReadLock();
尝试
{
返回(项目)的列表索引;
}
最后
{
_rwlock.exitradlock();
}
}
公共空白插入(整数索引,T项)
{
_rBlock.EnterWriteLock();
尝试
{
_列表。插入(索引,项目);
}
最后
{
_rBlock.ExitWriteLock();
}
}
公共T此[int索引]
{
得到
{
_rwlock.EnterReadLock();
尝试
{
返回列表[索引];
}
最后
{
_rwlock.exitradlock();
}
}
设置
{
_rBlock.EnterWriteLock();
尝试
{
_列表[索引]=值;
}
最后
{
_rBlock.ExitWriteLock();
}
}
}
公共IEnumerator GetEnumerator()
{
_rwlock.EnterReadLock();
尝试
{
foreach(列表中的var项目)
{
收益回报项目;
}
}
最后
{
_rwlock.exitradlock();
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
//为简洁起见,未实现其他方法
}
}

第一次设置它需要做一点工作,但之后它工作得很好。它支持任意数量的并发读卡器,或者只支持一个编写器

任何数量的读卡器都可以同时访问列表。如果线程想写入列表,它必须获得写锁。为了获得写锁,它会等待所有读卡器都完成。一旦线程请求写锁,任何线程都不能进入读锁。一旦写卡器完成,将允许读卡器通过


@Servy也有一个很好的建议。如果您的线程只是在阅读,并且定期从数据库中刷新列表(即完全构建一个新列表),那么就很容易按照他所说的去做。

在这种情况下,最好创建一个包含所需更改的新列表(即有附加项目,不添加某些项目等)然后只需设置缓存值以引用新列表。由于设置缓存值是原子的,因此您可以确保一旦有人从缓存中获取了值,它可能会有一点过时,但他们仍然能够很好地读取它。

我认为最好的解决方案是使用互斥设计模式来避免竞争条件。例如总之,.NET framework有一个互斥设计模式的标准实现;您可以在上阅读文档。

我总是发现很难从并发名称空间中匹配列表-有ConcurrentBag,但取决于您如何使用该列表,它不是一个很好的替代品,IMHO-readerwriterlock可能是一个有用的工具也可以构造。所以您的列表中有多个线程都在执行“foreach”?@Matt是的。这些线程不断地迭代t