当前位置: 首页 > news >正文

同步处理(LockContext),期待大家的意见

背景

关于它的名字

解决的问题

设计分析

代码展示

设计缺陷

 

背景

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

相关文章:

  • 高朋网13个地方分站整体被撤
  • 搜集点shell资料
  • VMware vCloud Director Administration Guide
  • Android应用程序在新的进程中启动新的Activity的方法和过程分析
  • SEO基本概念入门
  • Linux系统下启动MySQL的命令及相关知识
  • Forefront Client Security部署及配置
  • 一起谈.NET技术,走向ASP.NET架构设计——第七章:阶段总结,实践篇(中篇)...
  • android每日一问1【2011-09-06】
  • 深度剖析:远程控制软件如何实现隐性监控
  • Android应用程序进程启动过程的源代码分析(1)
  • JSF ( JavaServer Faces ) 介绍
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • Nginx+php(fastcgi)搭建LNMP
  • python random模块
  • 分享一款快速APP功能测试工具
  • 《剑指offer》分解让复杂问题更简单
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 【刷算法】求1+2+3+...+n
  • PHP 的 SAPI 是个什么东西
  • Spring Cloud中负载均衡器概览
  • SpriteKit 技巧之添加背景图片
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 简单数学运算程序(不定期更新)
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 数据结构java版之冒泡排序及优化
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​香农与信息论三大定律
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • #微信小程序:微信小程序常见的配置传旨
  • (1)bark-ml
  • (3)STL算法之搜索
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • .net core webapi 大文件上传到wwwroot文件夹
  • .net core控制台应用程序初识
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .Net Remoting常用部署结构
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件
  • .NET基础篇——反射的奥妙
  • .考试倒计时43天!来提分啦!
  • /bin/bash^M: bad interpreter: No such file ordirectory
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d
  • /var/lib/dpkg/lock 锁定问题
  • @media screen 针对不同移动设备
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [].shift.call( arguments ) 和 [].slice.call( arguments )