Linux多线程C++版(七) 线程互斥方式-----读写锁

读写锁在多线程并发控制中的应用与案例分析
本文介绍了读写锁的基本概念、创建与销毁、加锁与解锁操作,并通过ATM取款案例展示了读写锁在提高并发性能方面的优势。读写锁允许多个读线程并发访问,而写线程独占资源,从而优化了读密集型场景的性能。代码示例中展示了如何使用读写锁进行账户操作,确保线程安全。

1.读写锁基本概念
  • 线程使用互斥锁缺乏读并发性
  • 当读操作比较多,写操作比较少时,可使用读写锁提高线程读并发性
  • 读写锁数据类型 pthread_rwlock_t
2.读写锁创建和销毁
//定义读写锁
pthread_rwlock_t  rwlock;
//读写锁的初始化
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
//读写锁的销毁
int pthread_rwlock_destroy(pthread_rwlock_t *restrict rwlock);
  • 参数
    • rwlock:读写锁
    • attr:读写锁的属性
3.读写锁的加锁和解锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); //功能:加读锁
int pthread_rwlock_wdlock(pthread_rwlock_t *rwlock); //功能:加写锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); //功能:释放锁
返回:成功返回0,出错返回错误编号
  • 参数
    • rwlock:读写锁
4.代码了解读写锁
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//定义读写锁
pthread_rwlock_t rwlock;

int main(int argc,char *argv[]){
    if(argc<3){
        printf("-usage:%s [r|w] [r|w]/n",argv[0]);//"-usage代表你的程序
        exit(1);
    }
    //读写锁初始化
    pthread_rwlock_init(&rwlock,null);
    
    /*
    	strcmp函数用于比较两个字符串并根据比较结果返回整数。
    	基本形式为strcmp(str1,str2),
    	若str1=str2,则返回零;
    	若str1<str2,则返回负数;
    	若str1>str2,则返回正数。
    */
    if(!strcmp("r",argv[1])){
        //加读锁
        if(pthread_rwlock_rdlock(&rwlock) !=0){
            printf("first read lock failure\n");
        }else{
            printf("first read lock sucess\n");
        }
    }else if(!strcmp("w",argv[1])){
        //加写锁
        if(pthread_rwlock_wdlock(&rwlock) !=0){
            printf("first write lock failure\n");
        }else{
            printf("first write lock sucess\n");
        }
    }
    
    if(!strcmp("r",argv[2])){
        //加读锁
        if(pthread_rwlock_rdlock(&rwlock) !=0){
            printf("second read lock failure\n");
        }else{
            printf("second read lock sucess\n");
        }
    }else if(!strcmp("w",argv[2])){
        //加写锁
        if(pthread_rwlock_wdlock(&rwlock) !=0){
            printf("second write lock failure\n");
        }else{
            printf("second write lock sucess\n");
        }
    }
    
    //释放读写锁
    pthread_rwlock_unlock(&rwlock);
    pthread_rwlock_unlock(&rwlock);
    return 0;
}

程序代码输出:

​ 都是读锁,是都成功的。

​ 先读后写,读锁成功加上,加写锁堵塞,要等读锁释放

​ 先写后读,写锁成功加上,加读锁失败

​ 都是写锁,第一个写锁加上,第二次写锁失败

总结特性:读和读互不影响,读和写相互排斥,写和写相互排斥

在这里插入图片描述

5.线程互斥案例—ATM取钱–使用读写锁

头文件 account.h

#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__
#include <pthread.h>
//银行账户结构体
typedef struct{
    int code;//卡号
    double balance;//余额
    //定义一把互斥锁,用来对多线程操作
    //银行账户(共享资源)进行加锁保护
    /*
    	建议互斥锁和账户(共享资源)绑定一起,用来锁定一个账户(共享资源)
    	尽量不设置全局变量,否则肯能出现一把锁去锁几百个账户,导致并发性能降低
    */
    //pthread_mutex_t mutex; 定义互斥锁
    //定义读写锁
    pthread_rwlock_t  rwlock;
    
}Account;
//创建账户
extern Account* creat_account(int code,double balance);
//销毁账户
extern void destory_account(Account *a);
//取款
extern double withdraw(Account *a,double amt);
//存款
extern double deposit(Account *a,double amt);
//查看账户余额
extern double get_balance(Account *a);
#endif

功能文件account.c

#include "account.h"
#include <malloc.h>
#include <assert.h>
#include <string.h>

//创建账户
Account* creat_account(int code,double balance){
    //创建账户在堆当中
    Account *a = (Account*)malloc(sizeof(Account));
    assert(a != NULL);//用来判断a指针所需要开辟的空间,开辟成功了吗,成功就继续,否则就程序终止运行。
    a->code = code;
    a->balance = balance;
    //对读写锁进行初始化
    pthread_rwlock_init(&a->rwlock,null);
    return a;
}
//销毁账户
void destory_account(Account *a){
    assert(a != NULL);
    //销毁读写锁
    pthread_rwlock_destroy(&a->rwlock)
    free(a);//释放空间
}
//取款
double withdraw(Account *a,double amt){
    assert(a != NULL);//判断指针a是否为空
    /*
    	从成功上锁,到释放锁之间对共享资源操作的区间称为临界区
    */
    //加写锁
    pthread_rwlock_wrlock(&a->rwlock);
        
    if(amt < 0 || amt > a->balance){
        //释放读写锁
        pthread_rwlock_unlock(&a->rwlock);
        return 0.0;
    }
    double balance = a->balance;
    sleep(1);
    balance -= amt;
    a->balance = balance;
    //释放读写锁
    pthread_rwlock_unlock(&a->rwlock);
    return amt;
}
//存款
double deposit(Account *a,double amt){
   assert(a != NULL);
   //加写锁
   pthread_rwlock_wrlock(&a->rwlock);//对共享共享资源(账户)加锁
   if(amt < 0){
       //释放读写锁
       pthread_rwlock_unlock(&a->rwlock);
       return 0.0;
   }
    double balance = a->balance;
    sleep(1);
    balance += amt;
    a->balance = balance;
    //释放读写锁
    pthread_rwlock_unlock(&a->rwlock);
    return amt;
}
//查看账户余额
double get_balance(Account *a){
    assert(a != NULL);
    //加读锁
    pthread_rwlock_rdlock(&a->rwlock);//对共享共享资源(账户)加锁
    double balance = a->balance;
    //释放读写锁
    pthread_rwlock_unlock(&a->rwlock);
    return balanec;
}

执行文件 account_test.c

#include "account.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//操作者的结构体
typedef struct{
    char  name[20];//操作者姓名
    Account *account;//账户
    double amt;//金额
}OperArg
//定义取款操作的线程运行函数
void* withdraw_fn(void *arg){
    OperArg *oa = (OperArg*)arg;
    //deposit存款函数
    double amt = deposit(oa->account,oa->amt);
    printf("%8s(0x%lx) deposit %f from account %d/n",oa->name,pthread_self(),amt,oa->account->code);
    return (void*)0;
}
//定义存款操作的线程运行函数
void* deposit_fn(void *arg){
    OperArg *oa = (OperArg*)arg;
    //withdraw取款函数
    double amt = withdraw(oa->account,oa->amt);
    printf("%8s(0x%lx) withdraw %f from account %d/n",oa->name,pthread_self(),amt,oa->account->code);
    return (void*)0;
}
//定义查看银行账户的线程运行函数
void* check_fn(void *arg){
    
}
int main(void){
    int err;
    pthread_t boy,girl;
    Account *a = create_account(10001,10000)//卡号,余额
        
    OperArg o1 , o2;//两个操作者
    strcpy(o1.name,"boy");//strcpy()把第二个参数值,放到第一个参数中
    o1.account = a;
    o1.amt = 10000;
    
    strcpy(o2.name,"girl");
    o2.account = a;
    o2.amt = 10000;
    
    //启动两个子线程(boy和girl)同时去操作同一个银行账户
    if((err = pthread_create(&boy,null,withdraw_fn,(void*)&o1)!=0){
        printf("pthread create error");
    }
    if((err = pthread_create(&girl,null,withdraw_fn,(void*)&o2)!=0){
        printf("pthread create error");
    }
    
    pthread_join(boy,null);
    pthread_join(girl,null);
       
    //查看账户余额
    printf("account balance %f/n",get_balance(a));
    //销毁账户
    destroy_account(a);
    return 0;
}

程序运行结果:

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Unknown To Known

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值