zoukankan      html  css  js  c++  java
  • 读写锁

     读写锁的分配规则:

    (1)只要没有线程持有某个给定的读写锁用于写,那么任意数目的线程可以持有该读写锁用于读。

    (2)仅当没有线程持有某个给定的读写锁用于读或者写时,才能分配该读写锁用于写。

    即只要没有线程在修改某个给定的数据,那么任意数目的线程都可以拥有该数据的读访问权。仅当没有其它线程在

    读或修改某个给定的数据时,当前线程才可以修改它。

       这种对于某个给定资源的共享访问也称为共享-独占上锁,因为获取一个读写锁用于读称为共享锁,获取一个读写

    锁用于写称为独占锁。

       读写锁的数据类型为pthread_rwlock_t。如果这个类型的某个变量是静态分配的,那么可通过给它赋常值PTHREAD

    _RWLOCK_INITIALIZER来初始化它。下面是定义了基本的pthread_rwlock_t数据类型和操作读写锁的各个函数原型:

    #pragma once
    
    #include<pthread.h>
    #include<stdio.h>
    
    typedef struct
    {
        pthread_mutex_t rw_mutex;
        pthread_cond_t  rw_condreaders;
        pthread_cond_t  rw_condwriters;
        int             rw_magic;
        int             rw_nwaitreaders;
        int             rw_nwaitwriters;
        int             rw_refcount;    
    }my_pthread_rwlock_t;
    
    #define  RW_MAGIC  0x20180501
    #define MY_PTHREAD_RWLOCK_INITIALIZER {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER,RW_MAGIC,0,0,0}
    
    #define EBUSY 3
    typedef int  my_pthread_rwlockattr_t;
    int my_pthread_rwlock_destroy(my_pthread_rwlock_t *rw);
    int my_pthread_rwlock_rdlock(my_pthread_rwlock_t *rw);
    int my_pthread_rwlock_wrlock(my_pthread_rwlock_t *rw);
    int my_pthread_rwlock_unlock(my_pthread_rwlock_t *rw);
    int my_pthread_rwlock_tryrdlock(my_pthread_rwlock_t *rw);
    int my_pthread_rwlock_trywrlock(my_pthread_rwlock_t *rw);

      在my_pthread_rwlock_t数据类型中包含一个互斥锁、两个条件变量、一个标志以及三个计数器。无论何时检查或

    操作该结构,我们都必须持有其中的互斥锁成员rw_mutex,即都必须给其中的rw_mutex成员上锁。该结构初始化成

    功后,标志成员rw_magic就被设置成RW_MAGIC。所有函数都测试该成员,以检查调用者是否向某个已初始化的读

    写锁传递了指针。该读写锁被摧毁时,这个成员就被置为0。计数器成员之一的rw_refcount总是指示着本读写锁的

    当前状态:-1表示它是一个写入锁(任意时刻这样的锁只能有一个),0表示它是可用的,大于0的值则意味着它当

    前容纳着那么多的读写锁。

       my_pthread_rwlock_rdlock函数:

    int my_pthread_rwlock_rdlock(my_pthread_rwlock_t *rw)
    {
        int result;
        if(rw->rw_magic != RW_MAGIC)
            return -1;
        if((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
            return result;
    
        while(rw->rw_refcount< 0 || rw->rw_nwaitwriters> 0)
        {
            rw->rw_nwaitreaders++;
            result = pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex);
            rw->rw_nwaitreaders--;
            if(result != 0)
                break;
        }
        if(result == 0)
            rw->rw_refcount++;
        pthread_mutex_unlock(&rw->rw_mutex);
        return result;
    }

      如果rw_refcount小于0(意味着当前有一个写入者持有由调用者指定的读写锁),或者有线程正等着获取该读写锁

    的一个写入锁(rw_nwaitwriters大于0),那么我们无法获取该读写锁的一个读出锁。如果这两个条件中有一个为真

    ,我们就把rw_nwaitreaders加1。并在rw_condreaders条件变量上调用pthread_cond_wait。当给一个读写锁解锁时

    ,首先检查是否有任何等待着的写入者,若没有则检查是否有任何等待着的读出者。如果有读出者在等待,那就向

    rw_condreaders条件变量广播信号。取得读出锁后把rw_refcount加1,互斥锁即释放。

       my_pthread_rwlock_tryrdlock函数:

    int my_pthread_rwlock_tryrdlock(my_pthread_rwlock_t *rw)
    {
        int result;
        if(rw->rw_magic!= RW_MAGIC)
            return -1;
        if((result= pthread_mutex_lock(&rw->rw_mutex))!= 0)
            return result;
        if(rw->rw_refcount< 0||rw->rw_nwaitwriters> 0)
            result= EBUSY;
        else
            rw->rw_refcount++;
        pthread_mutex_unlock(&rw->rw_mutex);
        return result;
    }

       该函数它在尝试获取一个读出锁时并不阻塞。如果当前有一个写入者持有调用者指定的读写锁,或者有线程在等待

    该读写锁的一个写入锁,那就返回EBUSY错误。否则,通过把rw_refcount加1获取该读写锁。

        my_pthread_rwlock_wrlock函数:

    int my_pthread_rwlock_wrlock(my_pthread_rwlock_t *rw)
    {
        int result;
        if(rw->rw_magic != RW_MAGIC)
            return -1;
    
        if((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
            return result;
    
        while(rw->rw_refcount != 0)
        {
            rw->rw_nwaitwriters++;
            result = pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex);
            rw->rw_nwaitwriters--;
            if(result != 0)
                break;
        }
        if(result == 0)
            rw->rw_refcount = -1;
    
        pthread_mutex_unlock(&rw->rw_mutex);
        return result;
    }

       只要有读出者持有由调用者指定的读写锁的读出锁,或者有一个写入者持有该读写锁的唯一写入锁(两者都是rw_re

    fcount不为0的情况),调用线程就得阻塞。为此,我们把rw_nwaitwriters加1,然后在rw_condwriters条件变量上调用

    pthread_cond_wait。向条件变量发送信号的前提是:它所在的读写锁被释放,并且有写入者正在等待。取得写入锁后

    把rw_refcount置为-1。

       my_pthread_rwlock_trywrlock函数:

    int my_pthread_rwlock_trywrlock(my_pthread_rwlock_t *rw)
    {
        int result;
        if(rw->rw_magic!= RW_MAGIC)
            return -1;
        if((result= pthread_mutex_lock(&rw->rw_mutex))!= 0)
            return result;
        if(rw->rw_refcount!= 0)
            result= EBUSY;
        else
            rw->rw_refcount= -1;
        pthread_mutex_unlock(&rw->rw_mutex);
        return result;
    }

       如果rw_refcount不为0,那么由调用者指定的读写锁或者由一个写入者持有,或者一个或多个读出者持有,因为返回

    一个EBUSY错误。否则,获取该读写锁的写入锁,并把rw_refcount置为-1。

       my_pthread_rwlock_unlock函数:

    int my_pthread_rwlock_unlock(my_pthread_rwlock_t *rw)
    {
        int result;
        if(rw->rw_magic != RW_MAGIC)
            return -1;
        if((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
            return result;
    
        if(rw->rw_refcount > 0)
            rw->rw_refcount--;
        else if(rw->rw_refcount == -1)
            rw->rw_refcount = 0;
        else
            printf("unlock error.
    ");
    
        if(rw->rw_nwaitwriters > 0)
        {
            if(rw->rw_refcount == 0)
            {
                result = pthread_cond_signal(&rw->rw_condwriters);
            }
        }
        else if(rw->rw_nwaitreaders > 0)
            result = pthread_cond_broadcast(&rw->rw_condreaders);
    
        pthread_mutex_unlock(&rw->rw_mutex);
        return result;
    }

       如果rw_refcount当前大于0,那么有一个读出者(即调用线程)准备释放一个读出锁。如果rw_refcount当前为-1,那

    么一个写入者(即调用线程)准备释放一个写入锁。如果有一个写入者在等待,那么一旦由调用者指定的读写锁变得可

    用(即它的引用计数变为0),就向rw_condwriters条件变量发送信号。只有一个写入者能够获取该读写锁,因此调用pt

    hread_cond_signal来唤醒一个线程。如果没有写入者在等待,但是有一个或多个读出者在等待,那就在rw_condreaders

    条件变量上调用pthread_cond_broadcast,因为所有等待着的读出锁都可以获取一个读出锁。一旦有一个写入者在等待

    ,我们就不给任何读出者授予读出锁,否则一个持续的读请求流可能永远阻塞某个等待着的写入者。

       my_pthread_rwlock_destroy函数:

    int my_pthread_rwlock_destroy(my_pthread_rwlock_t *rw)
    {
        if(rw->rw_magic!= RW_MAGIC)
            return -1;
        if(rw->rw_refcount!= 0||rw->rw_nwaitreaders!= 0||rw->rw_nwaitwriters!= 0)
            return(EBUSY);
        pthread_mutex_destroy(&rw->rw_mutex);
        pthread_cond_destroy(&rw->rw_condreaders);
        pthread_cond_destroy(&rw->rw_condwriters);
        rw->rw_magic= 0;
    
        return 0;
    }

       该函数在所有线程(包括调用者在内)都不再持有也不试图持有某个读写锁的时候摧毁该锁。首先检查由调用者指定

    的读写锁已不再使用中,然后给其中的互斥锁和两个条件变量成员调用合适的摧毁函数。

  • 相关阅读:
    UE4物理笔记
    lambda+mutable配合move实现单函数多程序域
    UE导航系统详
    cpp智能指针
    [转载]新手应该如何学习网站分析
    webpack 单独打包指定JS文件
    vue-cli axios ie9 问题
    [分享] 通过修改CSS自定义chrome滚动条样式
    日期格式化转换方法
    vue 路劲
  • 原文地址:https://www.cnblogs.com/XNQC1314/p/9183487.html
Copyright © 2011-2022 走看看