You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:41:24