zoukankan      html  css  js  c++  java
  • 系统程序员成长计划并发(三)(下)

    转载时请注明出处和作者联系方式
    文章出处:http://www.limodev.cn/blog
    作者联系方式:李先静 <xianjimli at hotmail dot com>

    嵌套锁与装饰模式

    嵌套锁的实现算法

    加锁:

      o如果没有任何线程加锁,就直接加锁,并且记录下当前线程的ID。
      o如果是当前线程加过锁了,就不用加锁了,只是将加锁的计数增加一。
      o如果其它线程加锁了,那就等待直到加锁成功,后继步骤与第一种情况相同。

    解锁:
      o如果不是当前线程加的锁或者没有人加锁,那这是错误的调用,直接返回。
      o如果是当前线程加锁了,将加锁的计数减一。如果计数大于0,说明当前线程加了多次,直接返回就行了。如果计数为0,说明当前线程只加了一次,则执行解锁动作。

    这个逻辑很简单,要做到兼容Locker的接口和平台无关,我们还需要引入装饰模式这个概念。装饰模式的功能是在于不改变对象的本质(接口)的前提 下,给对象添加附加的功能。和继承不同的是,它不是针对整个类的,而只是针对单个对象的。装饰这个名字非常直观的表现它的意义:在你自己的显示器上做点了 装饰,比如贴上一张卡通画:第一是它没有改显示器的本质,显示器还是显示器。第二是只有你自己的显示器上多了张卡通画,其它显示器没有影响。

    这里我们要对一把锁进行装饰,不改变它的接口,但给它加上嵌套的功能。下面我们看看在C语言里的实现方法:

    o 创建函数的原型。由于获取当前线程ID的函数是平台相关的,我们要用回调函数来抽象它。

    typedef int (*TaskSelfFunc)(void);
    Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self);

    这里可以看出:传入的是一把锁,返回的还是一把锁,没有改变的接口,但是返回的锁已经具有嵌套调用的功能了。

    o 嵌入锁的实现。

    私有信息:拥有锁的线程ID、加锁的计数,被装饰的锁和获取当前线程ID的回调函数。

    typedef struct _PrivInfo
    {
    int owner;
    int refcount;
    Locker* real_locker;
    TaskSelfFunc task_self;
    }PrivInfo;

    1.实现加锁函数:如果当前线程已经加锁,只是增加加锁计数,否则就加锁。

    static Ret  locker_nest_lock(Locker* thiz)
    {
    Ret ret = RET_OK;
    PrivInfo* priv = (PrivInfo*)thiz->priv;

    if(priv->owner == priv->task_self())
    {
    priv->refcount++;
    }
    else
    {
    if( (ret = locker_lock(priv->real_locker)) == RET_OK)
    {
    priv->refcount = 1;
    priv->owner = priv->task_self();
    }
    }

    return ret;
    }

    2.实现解锁函数:只有当前线程加的锁才能解锁,先减少加锁计数,计数为0时才真正解锁,否则直接返回。

    static Ret  locker_nest_unlock(Locker* thiz)
    {
    Ret ret = RET_OK;
    PrivInfo* priv = (PrivInfo*)thiz->priv;

    return_val_if_fail(priv->owner == priv->task_self(), RET_FAIL);

    priv->refcount--;
    if(priv->refcount == 0)
    {
    priv->owner = 0;
    ret = locker_unlock(priv->real_locker);
    }

    return ret;
    }

    o使用方法。除了创建方法稍有不同外,调用方法完全一样。

        Locker* locker = locker_pthread_create();
    Locker* nest_locker = locker_nest_create(locker, (TaskSelfFunc)pthread_self);
    DList* dlist = dlist_create(NULL, NULL, nest_locker);

    装饰模式最有用的地方在于,它给单个对象增加功能,但不是影响调用者,即使加了多级装饰,调用者也不用关心。

    本节示例代码请到这里下载。


    欢迎到Linux mobile development上交流

  • 相关阅读:
    【Mysql学习笔记】浅析mysql的binlog
    HBase 学习笔记---守护进程及内存调优
    字符集例子-同一字符不同字符集编码不同及导入导出的乱码
    随机访问
    格式化的代价
    读写文本文件
    缓冲
    加速I/O的基本规则
    序列化再探讨
    数据库I/O:CMP、Hibernate
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167571.html
Copyright © 2011-2022 走看看