读写锁

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了读写锁相关的知识,希望对你有一定的参考价值。

1、读写锁

  互斥锁:试图进入临界区的所有其他进程都阻塞住。

  读写锁:获取读写锁用于读和获取读写锁用于写作区分。

  读写锁分配规则:

  (1)、读锁:共享锁,此时可以有多个读锁,但是没有写锁。

  (2)、写锁:独占锁,此时在也没有任何的写/读锁。

  (3)、读写锁中,写锁优先抢占资源。

2、编程实现

  需要使用:pthread_rwlock_t  rwlock  //定义了一个读写锁变量;

  使用的API为:

函数
说明
pthread_rwlock_wrlock()
写锁
pthread_rwlock_rdlock()
读锁
pthread_rwlock_unlock()解锁

代码实现:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>

pthread_rwlock_t rwlock;

void* fun1(void *arg){
    pthread_rwlock_wrlock(&rwlock);
    printf("This is fun1, wlock\n");
    sleep(2);
    pthread_rwlock_unlock(&rwlock);
}

void* fun2(void *arg){
    pthread_rwlock_rdlock(&rwlock);
    printf("This is fun2, rlock\n");
    pthread_rwlock_unlock(&rwlock);

}

void* fun3(void *arg){
    pthread_rwlock_wrlock(&rwlock);
    printf("This is fun3, wlock\n");
    pthread_rwlock_unlock(&rwlock);
}

int main(void){
    pthread_t tid1, tid2[5], tid3[5];
    pthread_create(&tid1, NULL, fun1, NULL);
    sleep(1);
    int i;

    for(i = 0; i < 5; i++){
        pthread_create(&tid2[i], NULL, fun2, NULL); //读锁
    }
    for(i = 0; i < 5; i++){
        pthread_create(&tid3[i], NULL, fun3, NULL);  //写锁
    }

    pthread_join(tid1, NULL);
    for(i = 0; i < 5; i++){
        pthread_join(tid2[i], NULL);
        pthread_join(tid3[i], NULL);
    }
    return 0;
}

运行结果

技术分享

3、实现写锁优先

  因为系统内部是写锁优先,经查看源码,现在实现此功能;以下是要实现的.c文件。

技术分享

  代码如下:

(1)、utili.h

#include<unistd.h>
#include<stdio.h>
#include<pthread.h>

(2)、pthread_rwlock.h

#ifndef _PTHREAD_RWLOCK_H
#define _PTHREAD_RWLOCK_H

#include"utili.h"

enum {EINVAL, EBUSY};

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;     //<0   ==0   >0
}my_pthread_rwlock_t;

#define RW_MAGIC 0x2016911

#define MY_PTHREAD_RWLOCK_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,                                     PTHREAD_COND_INITIALIZER,                                      PTHREAD_COND_INITIALIZER,                                     RW_MAGIC,                                     0, 0, 0}

typedef int my_pthread_rwlockattr_t;

int my_pthread_rwlock_init(my_pthread_rwlock_t *rw, my_pthread_rwlockattr_t *at);
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);

#endif

(3)、pthread_rwlock_init.c

#include"pthread_rwlock.h"

int my_pthread_rwlock_init(my_pthread_rwlock_t *rw, my_pthread_rwlockattr_t *at){
    int result;
    if(at != NULL)
        return EINVAL;

    if((result = pthread_mutex_init(&rw->rw_mutex, NULL)) != 0)
        goto err1;
    if((result = pthread_cond_init(&rw->rw_condreaders, NULL)) != 0)
        goto err2;
    if((result = pthread_cond_init(&rw->rw_condwriters, NULL)) != 0)
        goto err3;
    rw->rw_nwaitreaders = 0;
    rw->rw_nwaitwriters = 0;
    rw->rw_refcount = 0;
    rw->rw_magic = RW_MAGIC;

    return 0;

err3:
    pthread_cond_destroy(&rw->rw_condreaders);
err2:
    pthread_mutex_destroy(&rw->rw_mutex);
err1:
    return result;
}

(4)、pthread_rwlock_wrlock.c

#include"pthread_rwlock.h"

int my_pthread_rwlock_wrlock(my_pthread_rwlock_t *rw){
    int result;
    if(rw->rw_magic != RW_MAGIC){
        return EINVAL;
    }   
    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;
}

(5)、pthread_rwlock_rdlock.c

#include"pthread_rwlock.h"

int my_pthread_rwlock_rdlock(my_pthread_rwlock_t *rw){
    int result;
    if(rw->rw_magic != RW_MAGIC)
        return EINVAL;
    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;
}

(6)、pthread_rwlock_unlock.c

#include"pthread_rwlock.h"

int my_pthread_rwlock_unlock(my_pthread_rwlock_t *rw){
    int result;
    if(rw->rw_magic != RW_MAGIC)
        return EINVAL;
    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("refcount error.\n");
    }   

    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;
}

(7)、pthread_rwlock_destroy.c

#include"pthread_rwlock.h"

int my_pthread_rwlock_destroy(my_pthread_rwlock_t *rw)
{
    if(rw->rw_magic != RW_MAGIC)
        return EINVAL;
    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;
}

(8)、test.c

#include"utili.h"
#include"pthread_rwlock.h"

my_pthread_rwlock_t rwlock = MY_PTHREAD_RWLOCK_INITIALIZER;

void* fun1(void *arg){
    my_pthread_rwlock_wrlock(&rwlock);
    printf("This is fun1. wrlock\n");
    sleep(5);
    printf("fun1 wake up.\n");
    my_pthread_rwlock_unlock(&rwlock);
}
void* fun2(void *arg){
    my_pthread_rwlock_rdlock(&rwlock);
    printf("This is fun2.rdlock.\n");
    my_pthread_rwlock_unlock(&rwlock);
}
void* fun3(void *arg){
    my_pthread_rwlock_wrlock(&rwlock);
    printf("This is fun3,wrlock.\n");
    my_pthread_rwlock_unlock(&rwlock);
}


int main(){
    pthread_t tid1, tid2[5],tid3[5];
    int i;
    pthread_create(&tid1, NULL, fun1, NULL);
    sleep(1);
    for(i=0; i<5; ++i){
        pthread_create(&tid2[i], NULL, fun2, NULL);
    }

    for(i=0; i<5; ++i){
        pthread_create(&tid3[i], NULL, fun3, NULL);
    }
    pthread_join(tid1, NULL);
    for(i=0; i<5; ++i){
        pthread_join(tid2[i], NULL);
        pthread_join(tid3[i], NULL);
    }

    return 0;
}

(9)、Makefile

OBJ=test.o pthread_rwlock_rdlock.o pthread_rwlock_unlock.o pthread_rwlock_wrlock.o pthread_rwlock_init
.o
SRC=test.c pthread_rwlock_rdlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c pthread_rwlock_init
.c
test:$(OBJ)
    gcc -o test $(OBJ) -lpthread
test.o:test.c
    gcc -o test.o -c test.c
pthread_rwlock_rdlock.o:pthread_rwlock_rdlock.c
    gcc -o pthread_rwlock_rdlock.o -c pthread_rwlock_rdlock.c 
pthread_rwlock_unlock.o:pthread_rwlock_unlock.c
    gcc -o pthread_rwlock_unlock.o -c pthread_rwlock_unlock.c
pthread_rwlock_wrlock.o:pthread_rwlock_wrlock.c
    gcc -o pthread_rwlock_wrlock.o -c pthread_rwlock_wrlock.c
pthread_rwlock_init.o:pthread_rwlock_init.c
    gcc -o pthread_rwlock_init.o -c pthread_rwlock_init.c
.PHONY:clean

clean:
    rm *.o test

运行结果:

技术分享

这样我们自己就实现了写锁优先了,根据其原理,我们就可以改写为读锁优先。



本文出自 “11586096” 博客,请务必保留此出处http://11596096.blog.51cto.com/11586096/1855582

以上是关于读写锁的主要内容,如果未能解决你的问题,请参考以下文章

互斥锁自旋锁读写锁和条件变量

ReentrantReadWriteLock场景应用

读写锁ReentrantReadWriteLock源代码浅析

锁,同步,可重入锁,读写锁(转)

我写的由 GCD 代码支持的读写器锁导致并行测试中的死锁

读写锁(ReadWriteLock)