【操作系统】读写锁(练习)
·

要在 C++ 中使用读写锁(read-write lock)来模拟银行账户管理系统,我们需要使用适当的同步机制来确保多线程访问共享资源时的安全性。C++ 标准库提供了 std::shared_mutex 来实现读写锁,它允许多个线程同时读取共享资源,但在写入时,只有一个线程可以访问资源。
读写锁的工作原理
- 读锁:多个线程可以同时持有读锁并访问资源,前提是没有线程持有写锁。
- 写锁:只有一个线程可以持有写锁,并且持有写锁的线程不能与其他线程同时访问资源。
示例:使用读写锁模拟银行账户管理
我们将通过 std::shared_mutex 来管理对银行账户余额(balance)的读写访问。模拟的步骤如下:
- 使用 std::shared_lock 进行读取操作(多个线程可以同时读取余额)。
- 使用 std::unique_lock 进行写操作(只有一个线程可以修改余额)。
- 使用多个线程来并发地模拟存款、取款等操作,并使用读写锁来确保同步。
#include <iostream>
#include <thread>
#include <shared_mutex>
#include <cstdlib>
#include <ctime>
#include <unistd.h> // For sleep()
using namespace std;
// 定义共享资源:账户余额和读写锁
int balance = 1000;
std::shared_mutex balance_mutex; // 读写锁
// 读操作:查看余额
void check_balance() {
std::shared_lock<std::shared_mutex> lock(balance_mutex); // 共享读锁
cout << "Current balance: " << balance << endl;
}
// 写操作:存款
void deposit(int amount) {
std::unique_lock<std::shared_mutex> lock(balance_mutex); // 独占写锁
balance += amount;
cout << "Deposited " << amount << ". New balance: " << balance << endl;
}
// 写操作:取款
void withdraw(int amount) {
std::unique_lock<std::shared_mutex> lock(balance_mutex); // 独占写锁
if (balance >= amount) {
balance -= amount;
cout << "Withdrew " << amount << ". New balance: " << balance << endl;
} else {
cout << "Insufficient funds for withdrawal of " << amount << endl;
}
}
// 模拟修改余额的线程
void modify_balance(int iteration) {
srand(time(0) + iteration); // 为每个线程设定不同的随机种子
// 模拟存款
int deposit_amount = rand() % 201 - 100; // 随机存款或取款(-100 到 100)
if (deposit_amount >= 0) {
deposit(deposit_amount);
} else {
withdraw(-deposit_amount); // 负数表示取款
}
// 休眠1秒,模拟其他操作
sleep(1);
}
int main() {
// 创建多个线程模拟银行账户的操作
thread t1(modify_balance, 1);
thread t2(modify_balance, 2);
thread t3(modify_balance, 3);
thread t4(modify_balance, 4);
thread t5(modify_balance, 5);
// 同时查看余额(模拟多个读线程)
thread reader1(check_balance);
thread reader2(check_balance);
thread reader3(check_balance);
// 等待所有线程执行完成
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
reader1.join();
reader2.join();
reader3.join();
cout << "Final balance: " << balance << endl;
return 0;
}
代码解释:
1、共享资源
balance是我们用来模拟银行账户余额的共享资源。balance_mutex是我们使用的读写锁,确保在多线程环境中对balance的操作是线程安全的。
2、操作
check_balance():使用std::shared_lock来加读锁(共享锁)。多个线程可以同时读取余额。deposit()和withdraw():使用std::unique_lock来加写锁(独占锁)。只有一个线程可以修改余额。
3、多线程
- 我们启动多个线程来模拟对
balance的修改,每个线程会随机存款或取款。 - 我们还启动多个读取线程来模拟同时读取余额。
4、锁的使用
- 在读取余额时,使用
std::shared_lock,多个线程可以同时读取balance。 - 在存款和取款时,使用
std::unique_lock,确保只有一个线程可以修改balance。
5、模拟并发操作
sleep(1)用来模拟每个线程操作的延迟,给其他线程一些机会执行。
运行效果:
每次运行程序时,程序会并发执行存款和取款操作,并且有多个线程在同时读取账户余额。通过读写锁,确保了数据的正确性和线程安全。
```cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<errno.h>
#include<sys/wait.h>
#include<mqueue.h>
#include<time.h>
int balance = 1000;
pthread_rwlock_t rwlock;
void *select_balance(void *arg) {
pthread_rwlock_rdlock(&rwlock);
sleep(rand() % 3 + 1);
printf("balance: %d\n", balance);
pthread_rwlock_unlock(&rwlock);
return NULL;
}
void *modify_balance(void *arg) {
pthread_rwlock_wrlock(&rwlock);
sleep(1);
balance += atoi((char *)arg);
printf("modify: %d, balance: %d\n", atoi((char *)arg), balance);
pthread_rwlock_unlock(&rwlock);
return NULL;
}
int main(int argc, char *argv[])
{
if (argc != 6) {
printf("参数数量错误,正确参数数量应为5个!\n");
return -1;
}
pthread_rwlock_init(&rwlock, NULL);
srand(time(NULL));
pthread_t tid[15];
for (int i = 0; i < 5; i++) {
pthread_create(&tid[i], NULL, modify_balance, argv[i + 1]);
}
for (int i = 5; i < 15; i++) {
pthread_create(&tid[i], NULL, select_balance, NULL);
}
for (int i = 0; i < 15; i++) {
pthread_join(tid[i], NULL);
}
pthread_rwlock_destroy(&rwlock);
return 0;
}
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)