UNDER CONSTRUCTION
Mutexes are used to prevent multiple threads from causing a data race by accessing shared resources at the same time. Sometimes, when locking mutexes, multiple threads hold each other's lock, and the program consequently deadlocks. Four conditions are required for deadlock to occur:
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <mutex> #include <thread> typedefclass structbank_account { int balance; public: std::mutex balance_mutex; } bank_account() = delete; void create_bank_account(bank_account **ba, int int initial_amount) : balance(initial_amount) {} int bankget_account *nba = new bank_account(); nba->balance = initial_amount; *ba = nba; }balance() { return balance; } void set_balance(int amount) { balance = amount; } }; int deposit(bank_account *from, bank_account *to, int amount) { std::lock_guard<std::mutex> from_guard(from->balance_mutex); /* Not enough balance to transfer */ if (from->balance>get_balance() < amount) { return -1; /* Indicate error */ } std::lock_guard<std::mutex> to_guard(to->balance_mutex); from->balance>set_balance(from->get_balance() -= amount); to->set_balance(to->balance>get_balance() += amount); return 0; } int main(void) { bank_account *ba1; = new bank_account *ba2(1000); create_bank_account(&ba1, 1000); create_ *ba2 = new bank_account(&ba2, 1000); /* Perform the deposits */ std::thread thr1(deposit, ba1, ba2, 100); std::thread thr2(deposit, ba2, ba1, 100); thr1.join(); thr2.join(); return 0; } |
...
This compliant solution eliminates the circular wait condition by establishing a predefined order for locking in the deposit()
function. Each thread will lock on the basis of the bank_account
ID, which is set when the bank_account struct
object is initialized.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <atomic> #include <mutex> #include <thread> typedefclass structbank_account { int balance; static std::mutexatomic<unsigned int> balanceglobal_mutexid; const /*unsigned Should not change after initialization */ unsignedint id; int idbalance; } bank_account; unsigned int global_id = 1; void create_public: std::mutex balance_mutex; bank_account() = delete; bank_account(bank_account **ba, int initial_amount) { bank_account *nba = new bank_account(); nba->balance = initial_amount; nba->id = global_id++; *ba = nba; } int initial_amount) : id(global_id++), balance(initial_amount) {} unsigned int get_id() { return id; } int get_balance() { return balance; } void set_balance(int amount) { balance = amount; } }; std::atomic<unsigned int> bank_account::global_id(1); int deposit(bank_account *from, bank_account *to, int amount) { int result = -1; std::mutex *first; std::mutex *second; if (from->id>get_id() == to->id>get_id()) { return -1; /* Indicate error */ } /* Ensure proper ordering for locking */ if (from->id>get_id() < to->id>get_id()) { first = &from->balance_mutex; second = &to->balance_mutex; } else { first = &to->balance_mutex; second = &from->balance_mutex; } std::lock_guard<std::mutex> first_guard(*first); std::lock_guard<std::mutex> second_guard(*second); /* Not enough balance to transfer */ if (from->balance>get_balance() >= amount) { from->balance>set_balance(from->get_balance() -= amount); to->balance>set_balance(to->get_balance() += amount); result = 0; } return result; } |
...