项目常用算法之 一个C#资源池的实现
这个资源池用来管理程序的宝贵资源。
主要的类是ResourcePool<T>。
用户可以通过调用GetResource方法请求一个资源,用完之后通过ReturnResource归还给资源池。由资源池决定什么时候释放多余的资源。
接口IResourceProvider<T>用来获得资源。
类ResourceTag<T>用来标志资源是否在用。
具体的就不多说了,请看代码。欢迎讨论。
先是测试代码:
1 using System;
2 using NUnit.Framework;
3 using System.Data.SqlClient;
4 public class SqlConnectionProvider: IResourceProvider<SqlConnection>
5 {
6 public SqlConnection Request()
7 {
8 SqlConnection con= new SqlConnection();
9 //在此打开数据库连接,因为ResourcePool要求管理那些能用的资源。
10 //con.Open();
11 return con;
12 }
13 public void Dispose(SqlConnection con)
14 {
15 //在此销毁对象
16 con.Dispose();
17 }
18 }
19 [TestFixture]
20 public class Test
21 {
22 [Test]
23 public void TestPool()
24 {
25 //此处初始化资源池,参数:一个资源提供类和一个最大资源池中最大资源数目
26 ResourcePool<SqlConnection> pool=ResourcePool<SqlConnection>.Instance(new SqlConnectionProvider(),10);
27
28 long resourceID;
29 SqlConnection con=pool.GetResource(out resourceID);
30 //在此处使用con对象
31
32 //用完就归还
33 pool.ReturnResource(ref con,resourceID);
34
35
36 }
37 }
(以上测试只是简单的演示功能,详细的测试代码跟项目其他类有关,贴上反而复杂)
具体实现:
1 /// <summary>
2 /// 资源池,可以往里面加入资源,也可以取出来
3 /// </summary>
4 /// <typeparam name="T"></typeparam>
5 public class ResourcePool<T> : IDisposable where T : class, IDisposable
6 {
7 private static ResourcePool<T> pool;
8 IResourceProvider<T> resourceProvider;
9 static int maxResource;
10
11 public static int MaxResource
12 {
13 get { return ResourcePool<T>.maxResource; }
14
15 }
16 private ResourcePool(IResourceProvider<T> resourceProvider, int maxResource)
17 {
18 this.resourceProvider = resourceProvider;
19 ResourcePool<T>.maxResource = maxResource;
20 resources = new Dictionary<long,ResourceTag<T>> ();
21 }
22 public int ResourceCount
23 {
24 get
25 {
26 return resources.Keys.Count;
27 }
28 }
29
30 static object key3 = new object();
31 /// <summary>
32 /// 返回一个资源池,采用单件模式。
33 /// </summary>
34 /// <param name="resourceProvider"></param>
35 /// <returns></returns>
36 public static ResourcePool<T> Instance(IResourceProvider<T> resourceProvider, int maxResource)
37 {
38 if (pool == null)
39 {
40 lock (key3)
41 {
42 if (pool == null)
43 {
44 pool = new ResourcePool<T>(resourceProvider, maxResource);
45 }
46 }
47 }
48 return pool;
49 }
50 Dictionary<long,ResourceTag<T>> resources;
51 /// <summary>
52 ///从资源池中提取资源
53 /// </summary>
54 /// <param name="resourID">向资源用户输出的resourceID,返回资源时用它来返回特定资源</param>
55 /// <returns></returns>
56 public T GetResource(out long resourID)
57 {
58 T result = null;
59 result = getFreeResource(out resourID);
60 return result;
61 }
62 object key1 = new object();
63 private T getFreeResource(out long resourID)
64 {
65 lock (key1)
66 {
67 foreach (long key in resources.Keys)
68 {
69 if (!resources[key].InUse)
70 {
71 resources[key].InUse = true;
72 resourID = key;
73 return resources[key].Resource;
74 }
75 }
76 //申请新资源
77 T res = resourceProvider.Request();
78 if (res == null)//申请资源失败
79 {
80 resourID = getNullResourceID();
81 return null;
82 }
83 else
84 {
85 ResourceTag<T> tag = new ResourceTag<T>(res, true);
86 long id = newResourceID();
87 resources.Add(id, tag);
88 resourID=id;
89 return res;
90 }
91 }
92 }
93
94 private long getNullResourceID()
95 {
96 return -1;
97 }
98 /// <summary>
99 /// 产生新的资源号
100 /// </summary>
101 /// <returns></returns>
102 private long newResourceID()
103 {
104 return DateTime.Now.Ticks;
105 }
106
107
108 /// <summary>
109 /// 返回资源
110 /// </summary>
111 /// <param name="resource">ref类型的参数,将在函数内部设为null,意味着返回后不能再用。</param>
112 /// <param name="resourceID">获取资源时得到的那个resourceID。如果返回一个不正确的id,将抛出异常。</param>
113 public void ReturnResource(ref T resource, long resourceID)
114 {
115 if (!resources.ContainsKey(resourceID))
116 {
117 throw new InvalidOperationException("试图归还一个非法的资源。");
118 }
119 returnRes(ref resource,resourceID);
120 }
121 object key2 = new object();
122 private void returnRes(ref T resource, long resourceID)
123 {
124 T toDispose = null;
125 lock (key2)
126 {
127 ResourceTag<T> tag = resources[resourceID];
128 tag.InUse = false;
129 resources.Remove(resourceID);//当前的id将作废,不能再用
130 resource = null;//将当前的resource置空,不能再用
131 if (resources.Keys.Count >= maxResource)//达到上限,将释放资源
132 {
133 toDispose = resource;
134 }
135 else
136 {
137 resources.Add(newResourceID(), tag);
138 }
139 }
140 if (toDispose != null)
141 {
142 resourceProvider.Dispose(toDispose);
143 }
144 }
145 #region IDisposable 成员 及 析构方法
146
147 public void Dispose()
148 {
149 Dispose(true);
150 }
151 ~ResourcePool()
152 {
153 Dispose(false);
154 }
155 public virtual void Dispose(bool isDisposing)
156 {
157 foreach (long key in resources.Keys)
158 {
159 resources[key].Resource.Dispose();//释放资源
160 }
161 if (isDisposing)
162 {
163 key1 = null;
164 key2 = null;
165 key3 = null;
166 resourceProvider = null;
167 }
168 }
169 #endregion
170
171 }
172 internal class ResourceTag<T>
173 {
174 private T resource;
175
176 internal T Resource
177 {
178 get { return resource; }
179 set { resource = value; }
180 }
181 private bool inUse;
182
183 internal bool InUse
184 {
185 get { return inUse; }
186 set { inUse = value; }
187 }
188 public ResourceTag(T resource, bool inUse)
189 {
190 Resource = resource;
191 InUse = inUse;
192 }
193
194 }
195 /// <summary>
196 /// 这个接口用来产生ResourcePool管理的资源,比如数据库连接对象等
197 /// </summary>
198 /// <typeparam name="T"></typeparam>
199 public interface IResourceProvider<T> where T : class, IDisposable
200 {
201 /// <summary>
202 /// 获得资源
203 /// </summary>
204 /// <returns>成功则返回资源对象,否则返回null</returns>
205 T Request();
206 void Dispose(T resource);
207 }