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;
}
程序运行结果:

读写锁在多线程并发控制中的应用与案例分析

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

被折叠的 条评论
为什么被折叠?



