基于C++ Threads的存钱罐线程模拟实现技术需求问询
嘿,这需求我熟!咱们用C++标准库的线程、互斥锁和条件变量就能轻松实现这个存钱罐模拟。核心就是解决存款(producer)和取款(consumer)的同步问题,保证取款操作不会在余额不足的时候瞎执行。
实现思路
要搞定这个同步问题,咱们需要两个关键工具:
- 互斥锁(
std::mutex):保护共享的存钱罐余额,避免多个线程同时读写导致数据混乱。 - 条件变量(
std::condition_variable):让取款线程在余额不足时进入等待状态,直到存款线程通知余额充足了再继续执行。
完整代码实现
我把存钱罐封装成了一个类,这样代码更整洁,也方便复用:
#include <iostream> #include <thread> #include <mutex> #include <condition_variable> #include <vector> #include <chrono> // 存钱罐类,封装核心状态和操作 class PiggyBank { private: int balance = 0; // 存钱罐余额 std::mutex mtx; // 保护余额的互斥锁 std::condition_variable cv; // 用于同步的条件变量 public: // 存款函数:接收存款金额作为参数 void deposit(int amount) { // lock_guard会自动管理锁的生命周期,超出作用域自动解锁 std::lock_guard<std::mutex> lock(mtx); balance += amount; std::cout << "[存款操作] 存入 " << amount << " 元 | 当前余额:" << balance << std::endl; // 通知所有等待的取款线程:余额更新了 cv.notify_all(); } // 取款函数:接收取款金额作为参数 void withdraw(int amount) { // unique_lock支持临时解锁,适合配合条件变量使用 std::unique_lock<std::mutex> lock(mtx); // 必须用while循环检查条件,防止虚假唤醒 while (balance < amount) { std::cout << "[取款操作] 余额不足(当前:" << balance << "),等待存款..." << std::endl; // 等待时自动释放锁,被唤醒后重新获取锁 cv.wait(lock); } balance -= amount; std::cout << "[取款操作] 取出 " << amount << " 元 | 当前余额:" << balance << std::endl; } // 可选:添加获取余额的方法,方便查看最终结果 int getBalance() { std::lock_guard<std::mutex> lock(mtx); return balance; } }; int main() { PiggyBank my_piggy; // 创建3个存款线程,每次存100元 std::vector<std::thread> producers; for (int i = 0; i < 3; ++i) { producers.emplace_back(&PiggyBank::deposit, &my_piggy, 100); // 模拟存款间隔,让同步效果更直观 std::this_thread::sleep_for(std::chrono::milliseconds(600)); } // 创建3个取款线程,每次取80元 std::vector<std::thread> consumers; for (int i = 0; i < 3; ++i) { consumers.emplace_back(&PiggyBank::withdraw, &my_piggy, 80); } // 等待所有存款线程完成 for (auto& t : producers) { t.join(); } // 等待所有取款线程完成 for (auto& t : consumers) { t.join(); } std::cout << "\n所有操作完成!最终余额:" << my_piggy.getBalance() << std::endl; return 0; }
关键细节解释
我特意标记了几个容易踩坑的点,你可得注意:
- 互斥锁的选择:存款用
std::lock_guard就够了,因为它从创建到销毁一直持有锁,自动释放;取款必须用std::unique_lock,因为cv.wait()需要临时解锁,让其他线程能操作余额。 - 循环检查条件:千万别用
if代替while来判断余额!因为线程可能会被虚假唤醒(明明没人通知,它自己醒了),循环检查能确保只有余额真的足够时才执行取款。 - 通知机制:存款完成后调用
cv.notify_all(),这样所有等待的取款线程都会被唤醒,重新检查余额。如果只想唤醒一个线程,也可以用cv.notify_one(),不过这里用notify_all更稳妥。
运行效果示例
运行后你会看到类似这样的输出(顺序可能因为线程调度略有不同):
[存款操作] 存入 100 元 | 当前余额:100 [取款操作] 取出 80 元 | 当前余额:20 [取款操作] 余额不足(当前:20),等待存款... [存款操作] 存入 100 元 | 当前余额:120 [取款操作] 取出 80 元 | 当前余额:40 [取款操作] 余额不足(当前:40),等待存款... [存款操作] 存入 100 元 | 当前余额:140 [取款操作] 取出 80 元 | 当前余额:60 所有操作完成!最终余额:60
内容的提问来源于stack exchange,提问作者idkts
相关产品推荐
相关产品推荐

