Normally, the output should always be 200.But the output of "totalMoney" sometimes a number less than 200. What is the issue here and how to correct it? Will somebody please help me?
Why the output of "totalMoney" sometimes a number less than 200 probably is that the stems from a lack of synchronization between the threads during the transfer process. The potential issue is in Bank::transferMoney method, where calling changeMoney on accountA and accountB separately.
void transferMoney(Account* accountA, Account* accountB, double amount) {
accountA->changeMoney(-amount);
accountB->changeMoney(amount);
}
This method releases the lock between the two operations, might resulting in inconsistencies in the total amount of money across the accounts.
void changeMoney(double amount) {
unique_lock lock(mMoneyLock);
mConditionVar.wait(lock, [this, amount] {
return mMoney + amount > 0;
});
mMoney += amount;
mConditionVar.notify_all();
}
What you can try to make transfer process is atomic. locking both accounts during the transfer
class Account {
public:
Account(string name, double money): mName(name), mMoney(money) {};
public:
void changeMoney(double amount) {
unique_lock lock(mMoneyLock);
mConditionVar.wait(lock, [this, amount] {
return mMoney + amount >= 0;
});
mMoney += amount;
mConditionVar.notify_all();
}
string getName() {
return mName;
}
double getMoney() {
// Locking
unique_lock lock(mMoneyLock);
return mMoney;
}
mutex& getMutex() {
return mMoneyLock;
}
private:
string mName;
double mMoney;
mutex mMoneyLock;
condition_variable mConditionVar;
};
Also try to use a std::scoped_lock to lock both accounts’ mutexes when performing the transfer.
class Bank {
public:
void addAccount(Account* account) {
mAccounts.insert(account);
}
void transferMoney(Account* accountA, Account* accountB, double amount) {
// Lock both accounts
scoped_lock lock(accountA->getMutex(), accountB->getMutex());
accountA->changeMoney(-amount);
accountB->changeMoney(amount);
}
double totalMoney() const {
double sum = 0;
for (auto a : mAccounts) {
sum += a->getMoney();
}
return sum;
}
private:
set<Account*> mAccounts;
};