博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
同步处理(LockContext),期待大家的意见
阅读量:7078 次
发布时间:2019-06-28

本文共 5805 字,大约阅读时间需要 19 分钟。

背景

关于它的名字

解决的问题

设计分析

代码展示

设计缺陷

 

背景

最近由于要处理很多同步的问题,所以写了不少这方面的代码。最为显著的有已经在blog上提到的。还有接下来要向大家展示的LockContext。

关于它的名字

首先,LockContext这个名称是否合适还值得商榷,因为这里面使用了Lock,但其解决的问题当某一个对象还未完成初始化时,所有被其处理的事件通知都要等待。关于名称,我没有多想,因为我的目的是为了解决当前的问题。所以,当你读完代码时,有了新的想法,欢迎你与我分享。

解决的问题

当控件的实例被创建后,控件开始了数据的初始化任务,由于控件需要加载的数据量大,由于网络等因素,使数据的加载时间长,因而使得控件的初始化过程耗时较长。

而在另外一方面,当控件的实例化完成后,控件已经能够事件通知(在我的具体环境下,事件通知是由服务器发出的)。

因此,问题就出来了:在控件初始化的过程中,处理事件通知,会导致怪异的错误。

有人可能要问,找到到底是什么样的事件通知导致了错误,这是可以分析的。但我这里的环境是,控件加载的数据量和数据种类多,与此同时,来至于服务器端的事件通知也多,就算是分析清楚了错误,将这个具体的错误解决,也不能保证这样的错误会在今后的维护工作中继续发生。

因此,就需要通过某种机制解决这个问题,即当控件处于初始化状态时,当前视图访问该控件的其它线程都会被挂起。当控件初始化完成后再执行这些挂起的任务。

设计分析

InitJob与RunJob

该类用于保证初始化线程被锁定。如果InitJob没有被创建或者没有被解锁,那么其它RunJob将不能加锁。当其中一个RunJob加锁后,其余的RunJob只能等待。

InitJob与RunJob等待锁的时间是有限的,如果在等待的时间内没有加锁成功那么Job实例的Failed将会返回true。这也使得使用该机制的代码能够体面的处理加锁失败问题。

你可以直接返回,如下面代码

using(var state = mLockContext.InitJob(null)){    if(state.Failed)        return;}

你也可以抛出异常来改变程序的流程,如以下代码

uisng(var state = mLockContext.Run(null)){    if(state.Failed)        throw new CustomizedException();}

 

想一个办法来体面地使用Job

正如上面的代码展示,我选择了using块的方式来体面地使用Job。这样将加锁和解锁过程体面地影藏起来。

using(var state = mLockContext.Run(null)){    //...}
 

如何使用

正如“解决的问题”块中提到的,要使用这样的代码,就得将其放在类的初始化方法、其它public方法和事件通知处理方法中,保证该类的入口都有mLockContext“把守”。

例如:

class AControl : Control{    private readonly LockContext mLockContext = new LockContext();    public bool InitializeData()    {        using(var state = mLockContext.Init(null))        {            if(state.Failed)               return false;            //initializing code        }    }   public void MethodA()   {        using(var state = mLockContext.Run(null))        {            if(state.Failed)               return;            //code for method a here         }    }    public void MethodB()   {        using(var state = mLockContext.Run(null))        {            if(state.Failed)               return;            //code for method b here         }    }}

 

代码展示

 

using System;using System.Collections.Generic;using System.Text;using System.Diagnostics;using System.Threading;namespace OpenCourse.OpenActivity.Windows.Views{    public class LockContext    {        private volatile bool mInitStarted = false;        private volatile bool mInitCompleted = false;        private object mLockObj = new object();        private readonly int mLockTimeInSeconds = 5;        public LockContext(int lockTimeInSeconds)        {            mLockTimeInSeconds = lockTimeInSeconds;        }        public LockContext() { }        public class InitJob : IDisposable        {            LockContext mContext;            public bool Failed            {                get;                private set;            }            public InitJob(bool state)            {                Failed = !state;            }            public InitJob(LockContext context)                : this(true)            {                mContext = context;                mContext.mInitStarted = true;                mContext.mInitCompleted = false;            }            #region IDisposable Members            public void Dispose()            {                if (mContext != null)                {                    mContext.mInitCompleted = true;                    mContext.mInitStarted = false;                    Monitor.Exit(mContext.mLockObj);                }            }            #endregion        }        public InitJob Init(string jobDescription)        {            if (!string.IsNullOrEmpty(jobDescription))                Trace.WriteLine(jobDescription + " try to enter the lock");            if (Monitor.TryEnter(mLockObj, mLockTimeInSeconds * 1000))            {                if (!string.IsNullOrEmpty(jobDescription))                    Trace.WriteLine(jobDescription + " enter the lock successfully");                return new InitJob(this);            }            else            {                if (!string.IsNullOrEmpty(jobDescription))                    Trace.WriteLine(jobDescription + " implementation fails due to the lock issue");                return new InitJob(false);            }        }        public class RunJob : IDisposable        {            public bool Failed { get; private set; }            private LockContext mContext;            public RunJob(bool state)            {                Failed = !state;            }            public RunJob(LockContext context)                : this(true)            {                mContext = context;            }            #region IDisposable Members            public void Dispose()            {                if (mContext != null)                    Monitor.Exit(mContext.mLockObj);            }            #endregion        }        public RunJob Run(string jobDescription)        {            if (!mInitStarted && !mInitCompleted)            {                return new RunJob(false);            }            if (!string.IsNullOrEmpty(jobDescription))                Trace.WriteLine(jobDescription + " tries to enter the lock");            if (Monitor.TryEnter(mLockObj, mLockTimeInSeconds * 1000))            {                if (!string.IsNullOrEmpty(jobDescription))                    Trace.WriteLine(jobDescription + " enter the lock successfully");                return new RunJob(this);            }            else            {                if (!string.IsNullOrEmpty(jobDescription))                    Trace.WriteLine(jobDescription + " implementation fails due to the lock issue");                return new RunJob(false);            }        }        public void ResetState()        {            mInitCompleted = false;            mInitStarted = false;        }    }}

设计缺陷

从上面的例子代码可以发现, mLockContext都是被用于public方法。但是,如果method a 调用了method b,那后果是method b不能成功执行,因为锁已经被method a占用了。

这个设计缺陷我也在想办法解决。欢迎大家的任何建议和意见。

 

 

 

转载于:https://www.cnblogs.com/czy/archive/2011/08/21/2148606.html

你可能感兴趣的文章
[LeetCode] Implement Magic Dictionary 实现神奇字典
查看>>
blender split mesh
查看>>
MongoDB官方C#驱动中查询条件Query用法
查看>>
vim插件ctags的安装和使用【转】
查看>>
Debian静态IP地址和DNS
查看>>
Java中Class.this和this的区别(转)
查看>>
jsp参数传递
查看>>
nutch2.x在eclipse+windows环境下运行遇到的一些问题的解决方案
查看>>
.Net Core 2.0 EntityFrameworkCore CodeFirst入门教程
查看>>
"软件随想录" 读书笔记
查看>>
windows下,下载pip安装
查看>>
nginx反向代理中proxy_set_header 运维笔记
查看>>
jQuery操作元素的class属性
查看>>
关于idea新建子目录时往父目录名字后叠加而不是树形结构的解决方法(转)
查看>>
HttpURLConnection和HttpClient的区别2(转)
查看>>
GMP大法教你重新做人(从入门到实战)
查看>>
视频教程制作软件与制作方法
查看>>
数据结构与算法 - 图论
查看>>
时间系统、进程的调度与切换
查看>>
跨域详解
查看>>