zoukankan      html  css  js  c++  java
  • 技术笔记:Delphi多线程应用读写锁

    在多线程应用中锁是一个很简单又很复杂的技术,之所以要用到锁是因为在多进程/线程环境下,一段代码可能会被同时访问到,如果这段代码涉及到了共享资源(数据)就需要保证数据的正确性。也就是所谓的线程安全。之前写过一篇着于Java线程安全的博客:链接

    我是在写一个服务端程序时应用到读写锁,在一个内存缓存。先来看看排斥锁的写法,代码如下:

    function TValueCalc.GetValue(const key: string): TCache;
    var
      objCache: TCache;
    begin
      Result := nil;  
      //加锁
      FRead2Lock.Enter;
      try
        objCache := GetCacheInstance.GetCache(sKey);
        if objCache <> nil then
        begin
          //缓存正在更新,直接退出,不让线程等待,以提高性能
          if objCache.IsUpdating then
            Exit;
          //是否过期,未过期直接返回
          if MilliSecondsBetween(Now, objCache.LastTime) < Expires then
          begin
            Result := objCache;
            Exit;
          end;
          
          objCache.IsUpdating := True;
        end;
        //更新缓存
        Result := UpdateCache(key);
      finally
        //释放锁
        FRead2Lock.Leave;
      end;
    end;

    但是这个缓存有一个特点,就是每个缓存项存活的时间很短,这就会导致大量的缓存更新操作,而这些更新操作由于业务不同耗时也不同。这就导致线程都在等待缓存的更新。为了解决这个问题引入了读写锁。让读锁可以在写数据时释放,让后面的线程继续执行查找缓存数据。

    function TValueCalc.GetValue(const key: string): TCache;
    var
      objCache: TCache;
    begin
      Result := nil;      
      FRead2Lock.Enter;
      try
        objCache := GetCacheInstance.GetCache(sKey);
        if objCache <> nil then
        begin
          //缓存正在更新,直接退出,不让线程等待,以提高性能
          if objCache.IsUpdating then
            Exit;
          //检查缓存是否过期
          if MilliSecondsBetween(Now, objCache.LastTime) < Expires then
          begin
            Result := objCache;
            Exit;
          end;
          
          objCache.IsUpdating := True;
        end;
        
        //先释放读锁,后面线程可以继续读数据
        FRead2Lock.Leave;
        //加写锁
        FWriteLock.Enter;
        try
          //更新缓存
          Result := UpdateCache(key);
        finally
          //数据更新完毕,重新加上读锁
          FRead2Lock.Enter;
          //释放写锁
          FWriteLock.Leave;
        end;
      finally
        //释放读锁
        FRead2Lock.Leave;
      end;
    end;

    读写锁是在进行写数据前先释放掉读锁,然后马上加上写锁,这样后续读缓存的线程就可以继续执行,不会等待。而同时写缓存已经上锁,这样就不会资源冲突。

    读写锁这样就可以大大提升读缓存的性能,也不会影响到缓存的更新了。

  • 相关阅读:
    N25_复杂链表的复制
    N24_二叉树中和为某一路径
    N23_判断是否为二叉搜索树的后序遍历序列
    N22_从上到下打印二叉树
    win7桌面小工具已停止工作解决办法
    C3P0数据库连接池使用
    js中的页面跳转
    怎么用js代码禁止浏览器的前进与后退?
    怎么在 Dos 下运行 PHP 和 MySQL 命令
    80端口被system 占用解决方法
  • 原文地址:https://www.cnblogs.com/5207/p/5133064.html
Copyright © 2011-2022 走看看