在Web中Session的功能很好用,因而想Winform中实现该功能,典型应用场景则是登录成功后,当一段时间不操做,则该会话过时,提示从新登录。缓存
测试代码多线程
示例说明:登录进去10s不操做或者访问Cache后10秒不操做,则会提示登录超时测试
1. 设计CacheContainer类,使用Dictionary存放变量,并添加互斥锁SyncRoot,避免多线程操做带来异常。this
2. CacheContainer内部的变量,若是持续10秒(测试使用的默认值)没有访问或操做,则自动移除该变量,并触发回调。spa
3. 当程序访问CacheContainer内部的变量,过时时间从当前时间开始计时。线程
4. 变量第一次计时在加入CacheContainer时。设计
具体代码以下:code
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace WindowsFormsApplication1 { public sealed class CacheContainer { //互斥锁 private object SyncRoot = new object(); //对象字典 private Dictionary<string, CacheObj> dic = new Dictionary<string, CacheObj>(); internal class CacheObj : IDisposable { //公有变量 public object Value { get; set; } public int Expired { get; set; } public WaitCallback callback { get; set; } public AutoResetEvent ar = new AutoResetEvent(false); public TimeSpan Timeout { get { return TimeSpan.FromSeconds(Expired); } } public CacheObj(object value, int expired = 10) { Value = value; Expired = expired; callback = new WaitCallback((obj) => { Console.WriteLine("{0}:已过时,过时时间:{1}", obj, DateTime.Now); }); } public void Dispose() { GC.SuppressFinalize(this); } ~CacheObj() { Dispose(); } } private static CacheContainer container = new CacheContainer(); private CacheContainer() { } public static CacheContainer GetInstance() { return container; } public object this[string key] { get { //访问变量成功,则时间从新计时 CacheObj cache; lock (SyncRoot) { if (dic.TryGetValue(key, out cache)) { cache.ar.Set(); return cache.Value; } } return null; } set { //经过属性添加参数,有则覆盖,无则添加,操做完毕从新计时 CacheObj cache; lock (SyncRoot) { if (dic.TryGetValue(key, out cache)) { cache.Value = value; cache.ar.Set(); } else Add(key, value); } } } public void Add(string key, object value) { lock (SyncRoot) dic.Add(key, new CacheObj(value)); AutoCheck(key); } public void Add(string key, object value, int expired) { lock (SyncRoot) dic.Add(key, new CacheObj(value, expired)); AutoCheck(key); } public void Add(string key, object value, int expired, WaitCallback callback) { lock (SyncRoot) dic.Add(key, new CacheObj(value, expired) { callback = callback }); AutoCheck(key); } private void AutoCheck(string key) { //开启一个子线程去控制变量的过时 ThreadPool.QueueUserWorkItem(new WaitCallback((obj) => { CacheObj tmpCache; while (true) { //从字典中取出对象 lock (SyncRoot) tmpCache = dic[key]; //打印变量过时时间 Console.WriteLine("{0} 等待销毁变量 时间为:{1}秒", DateTime.Now, tmpCache.Expired); //记录开始时间 var timeStart = DateTime.Now; //中断,超时时间一到,自动向下执行 tmpCache.ar.WaitOne(TimeSpan.FromSeconds(tmpCache.Expired)); //检查时间是否已经达到超时时间,超时则移除该信息,并触发回调 if ((DateTime.Now - timeStart) >= tmpCache.Timeout) { lock (SyncRoot) dic.Remove(key); if (tmpCache.callback != null) tmpCache.callback(tmpCache.Value); break; } } })); } public void Remove(string key) { lock (SyncRoot) { CacheObj cache; if (dic.TryGetValue(key, out cache)) { cache.Expired = 0; cache.ar.Set(); } } } } }
CacheContainer中的变量,均是在线程池里有个线程去检测它,也就是说有10个变量,线程池里就会多10个子线程,这样会不会不太好。orm
该方法仅是抛砖引玉,不知道在Winform中实现缓存变量xx分钟这样的功能有没有更好的方法,欢迎赐教,谢谢!对象