使用pthread互斥体+条件变量实现读写锁

//最近在学习《高性能mysql》的时候,提到了读写锁,读锁是共享锁,写锁是排它锁,还有项目中也提到了读写锁的概念。进而想弄清楚,读写锁的实现机制,

//只有明白了读写锁的实现机制,才能明白读写锁对性能的影响

//本程序采用的是pthread_mutex_t互斥体+pthread_cond_t条件变量的方式去模拟读写锁的实现机制

//希望能够帮助刚刚接触pthread线程的朋友,如何去使用互斥体和条件变量来实现多线程协同工作

//编译方式gcc -o rwlock rwlock.c -lpthread

//作者在多线程领域也研究了一段时间,不过,在平时的项目中还是尽可能的避免使用锁,一方面加锁会降低程序的维护性,另外极易产生并发错误

//为了尽可能的做到无锁编程,需要结合pthread提供的线程特有资源来做。

//对于基本数据类型直接使用__thread关键字来实现线程独立的全局变量

//闲话少叙,本程序中需要注意volatile关键字修饰的变量,主要是防止编译器做优化。由于每个线程有自己独立的寄存器,当编译器做了优化之后,很有可能数据被加载

//到寄存器,并做了修改,也不会立即回写,当另一个线程将该数据加载到寄存器的时候,就不是最新的数据了,这样即使上锁,也不能保证数据不会被破坏

//由于作者资历不深,如果程序中有什么错误,希望大家多多指出,作者不甚感激

#include <unistd.h>

#include <pthread.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>


#define READ_THREAD_NUM 10


#define WRITE_THREAD_NUM 5


#define RES_LEN  10


#define log_error_by_errno(savedErrno) do { \

char errMsg[255];   \

strerror_r(savedErrno,errMsg,sizeof(errMsg));  \

printf("errno:[%d]----errMsg:[%s]---line:[%d]---function:[%s]\n",savedErrno,errMsg,__LINE__,__FUNCTION__);  \

exit(EXIT_FAILURE);  \

}while(0);


typedef struct Lock

{

    pthread_mutex_t lock;

    pthread_cond_t cond;

    volatile int owners;//we must add the volatile key word

}Lock_t;


typedef struct RW_Lock

{

    Lock_t rLock;

    Lock_t wLock;

    volatile int res[RES_LEN];

}RW_Lock_t;


void readLock(RW_Lock_t * prwLock)

{

    int ret;

    if((ret = pthread_mutex_lock(&prwLock->rLock.lock)))

    {

        log_error_by_errno(ret);

    }

    while(prwLock->rLock.owners != 0)

    {

        if((ret = pthread_cond_wait(&prwLock->rLock.cond,&prwLock->rLock.lock)))

        {

            log_error_by_errno(ret);

        }

    }

    if((ret = pthread_mutex_unlock(&prwLock->rLock.lock)))

    {

        log_error_by_errno(ret);

    }

    //mark the write lock owner

    if((ret = pthread_mutex_lock(&prwLock->wLock.lock)))

    {

        log_error_by_errno(ret);

    }

    prwLock->wLock.owners++;

    printf("wlock.owners:[%d]---line:[%d]---function:[%s]--thread:[%u]\n",prwLock->wLock.owners,__LINE__,__FUNCTION__,pthread_self());

    if((ret = pthread_mutex_unlock(&prwLock->wLock.lock)))

    {

        log_error_by_errno(ret);

    }

}

void readUnLock(RW_Lock_t * prwLock)

{

    int ret;

    if((ret = pthread_mutex_lock(&prwLock->wLock.lock)))

    {

        log_error_by_errno(ret);

    }

    prwLock->wLock.owners--;

    printf("wlock.owners:[%d]---line:[%d]---function:[%s]--thread:[%u]\n",prwLock->wLock.owners,__LINE__,__FUNCTION__,pthread_self());

    if(prwLock->wLock.owners == 0)

    {

        if((ret = pthread_cond_signal(&prwLock->wLock.cond)))

        {

            log_error_by_errno(ret);

        }

    }

    if((ret = pthread_mutex_unlock(&prwLock->wLock.lock)))

    {

        log_error_by_errno(ret);

    }

}

void writeLock(RW_Lock_t * prwLock)

{

    int ret;

    if((ret = pthread_mutex_lock(&prwLock->rLock.lock)))

    {

        log_error_by_errno(ret);

    }

    prwLock->rLock.owners++;

    printf("rlock.owners:[%d]---line:[%d]---function:[%s]--thread:[%u]\n",prwLock->rLock.owners,__LINE__,__FUNCTION__,pthread_self());

    if((ret = pthread_mutex_unlock(&prwLock->rLock.lock)))

    {

        log_error_by_errno(ret);

    }

    if((ret = pthread_mutex_lock(&prwLock->wLock.lock)))

    {

        log_error_by_errno(ret);

    }

    while(prwLock->wLock.owners != 0)

    {

        if((ret = pthread_cond_wait(&prwLock->wLock.cond,&prwLock->wLock.lock)))

        {

            log_error_by_errno(ret);

        }

    }

}

void writeUnLock(RW_Lock_t * prwLock)

{

    int ret;

    if((ret = pthread_mutex_unlock(&prwLock->wLock.lock)))

    {

        log_error_by_errno(ret);

    }

    if((ret = pthread_mutex_lock(&prwLock->rLock.lock)))

    {

        log_error_by_errno(ret);

    }

    prwLock->rLock.owners--;

    printf("rlock.owners:[%d]---line:[%d]---function:[%s]--thread:[%u]\n",prwLock->rLock.owners,__LINE__,__FUNCTION__,pthread_self());

    if(prwLock->rLock.owners == 0)

    {

        if((ret = pthread_cond_signal(&prwLock->rLock.cond)))

        {

            log_error_by_errno(ret);

        }

    }

    if((ret = pthread_mutex_unlock(&prwLock->rLock.lock)))

    {

        log_error_by_errno(ret);

    }

}

void * readFun(void * param)

{

    for(; ;)

    {

        srand(time(NULL));

        RW_Lock_t * prwLock = (RW_Lock_t *)param;

        readLock(prwLock);

        //mark 进入临界区

        //do something

        printf("res:[");

        int i = 0;

        for(i = 0; i < sizeof(prwLock->res)/sizeof(prwLock->res[0]); ++i)

        {

            printf("%d\t",prwLock->res[i]);

        }

        printf("]\n");

        //mark 退出临界区

        readUnLock(prwLock);

        sleep(rand() % 2 + 1);

    }

    return NULL;

}


void * writeFun(void * param)

{

    for(; ;)

    {

        srand(time(NULL));

        RW_Lock_t * prwLock = (RW_Lock_t *)param;

        writeLock(prwLock);

        //进入临界区

        //do something

        int index = rand()%RES_LEN;

        prwLock->res[index] = rand() % RES_LEN;

        //退出临界区

        writeUnLock(prwLock);

        sleep(rand() % 3 + 1);

    }

    return NULL;

}



int main(void)

{

    pthread_t rthreadPool[READ_THREAD_NUM];

    pthread_t wthreadPool[WRITE_THREAD_NUM];

    RW_Lock_t rwLock;

    RW_Lock_t * prwLock = &rwLock;

    int ret;

    if((ret = pthread_mutex_init(&prwLock->rLock.lock,NULL)))

    {

        log_error_by_errno(ret);

    }

    if((ret = pthread_cond_init(&prwLock->rLock.cond,NULL)))

    {

        log_error_by_errno(ret);

    }

    prwLock->rLock.owners = 0;

    

    if((ret = pthread_mutex_init(&prwLock->wLock.lock,NULL)))

    {

        log_error_by_errno(ret);

    }

    if((ret = pthread_cond_init(&prwLock->wLock.cond,NULL)))

    {

        log_error_by_errno(ret);

    }

    prwLock->wLock.owners = 0;

    memset(&prwLock->res,0,sizeof(prwLock->res));

    int i = 0;

    for(i = 0; i < READ_THREAD_NUM; ++i)

    {

        if((ret = pthread_create(&rthreadPool[i],NULL,readFun,prwLock)))

        {

            log_error_by_errno(ret);

        }

    }

    for(i = 0; i <WRITE_THREAD_NUM; ++i)

    {

        if((ret = pthread_create(&wthreadPool[i],NULL,writeFun,prwLock)))

        {

            log_error_by_errno(ret);

        }

    }

    for(i = 0; i < READ_THREAD_NUM; ++i)

    {

        pthread_join(rthreadPool[i],NULL);

    }

    for(i = 0; i < WRITE_THREAD_NUM; ++i)

    {

        pthread_join(wthreadPool[i],NULL);

    }

    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值