#include<iostream>
#include<atomic>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<unordered_set>
#include<set>
using namespace std;
std::mutex mtx;
std::condition_variable cv;
class Count // 账户
{
private:
int money;
public:
Count(int m = 0) : money(m) {}
~Count() {}
public:
bool operator<(const Count& _X) const { return money < _X.money; }
int getMoney() { return money; }
void setMoney(int m) { money = m; }
};
class Account // 保证账户交易的线程安全
{
public:
static Account* getInstance()
{
static Account a; // 只有一个实例,所有转账操作共用该实例
return &a;
}
void apply(Count& A, Count& B)
{
unique_lock<mutex> lc(mtx);
// 当前转账的双方,其中一人(或两人)有其他转账业务
while (s.count(A) > 0 || s.count(B) > 0)
{
cv.wait(lc); // 线程阻塞 ,等待被唤醒
}
// 到达这一步时,在交易队列中(s),没有A或B的其他业务。此时将AB双方放入交易队列
s.insert(A);
s.insert(B);
}
void free(Count&A, Count&B)
{ // 当前交易双方交易完毕,从交易队列中踢出
unique_lock<mutex> lc(mtx);
s.erase(A);
s.erase(B);
cv.notify_all(); // 唤醒其他等待的线程
}
~Account() = default; // c11
private:
Account() {}
Account(const Account&) = delete;
Account& operator=(const Account&) = delete;
std::set<Count> s;
};
void thread_fun(Count& A, Count& B, int money, string desc) // A --> B money
{
Account* acc = Account::getInstance();
acc->apply(A, B); // AB如果有其他转账流程时,当前这一步阻塞。
if (A.getMoney() >= money) // 转账操作
{
A.setMoney(A.getMoney() - money);
B.setMoney(B.getMoney() + money);
cout << desc << "转账成功 : " << endl;
cout << money << endl;
}
else
{
cout << desc << "余额不足! " << endl;
}
acc->free(A, B);
}
int main()
{
Count A(1000);
Count B(1000);
Count C(2000);
// 开始转账
thread t1(thread_fun, std::ref(A), std::ref(B), 200, "A->B: "); // A --> B; // mySQL
thread t2(thread_fun, std::ref(B), std::ref(A), 500, "B->A: "); // B -- > A;
thread t3(thread_fun, std::ref(C), std::ref(B), 200, "C->B: ");
thread t4(thread_fun, std::ref(C), std::ref(A), 300, "C->A: ");
t1.join();
t2.join();
t3.join();
t4.join();
cout << "A remaining money : " << A.getMoney() << endl;
cout << "B remaining money : " << B.getMoney() << endl;
cout << "C remaining money : " << C.getMoney() << endl;
return 0;
}
银行转账问题 | 线程安全
于 2021-04-04 22:02:46 首次发布