fork download
  1. #include <functional>
  2. #include <iostream>
  3. #include <mutex>
  4. #include <thread>
  5.  
  6. typedef long Money; //In minor unit.
  7.  
  8. class Account {
  9. public:
  10. bool transfer(Account& to,const Money amount);
  11. Money get_balance() const;
  12. Account(const Money deposit=0) : balance{deposit} {}
  13. private:
  14. mutable std::mutex lock;
  15. Money balance;
  16. };
  17.  
  18. namespace{
  19. std::less<void*> less{};
  20. std::equal_to<void*> equal_to{};
  21. }
  22.  
  23. bool Account::transfer(Account& to,const Money amount){
  24. std::unique_lock<decltype(this->lock)> flock{this->lock,std::defer_lock};
  25. std::unique_lock<decltype(to.lock)> tlock{to.lock,std::defer_lock};
  26. if(less(&this->lock,&to.lock)){
  27. flock.lock();
  28. tlock.lock();
  29. } else if(equal_to(&this->lock,&to.lock)) {
  30. flock.lock();
  31. } else {
  32. tlock.lock();
  33. flock.lock();
  34. }
  35. this->balance-=amount;
  36. to.balance+=amount;
  37. return true;
  38. }
  39.  
  40. Money Account::get_balance() const{
  41. const std::lock_guard<decltype(this->lock)> guard{this->lock};
  42. return this->balance;
  43. }
  44.  
  45. void hammer_transfer(Account& from,Account& to,const Money amount, const int tries){
  46. for(int i{1};i<=tries;++i){
  47. from.transfer(to,amount);
  48. }
  49. }
  50.  
  51. int main() {
  52. constexpr Money open_a{ 200000L};
  53. constexpr Money open_b{ 100000L};
  54. constexpr Money tran_ab{10};
  55. constexpr Money tran_ba{3};
  56. constexpr Money tran_aa{7};
  57.  
  58. Account A{open_a};
  59. Account B{open_b};
  60.  
  61. std::cout << "A Open:" << A.get_balance() << '\n';
  62. std::cout << "B Open:" << B.get_balance() << '\n';
  63.  
  64. constexpr long tries{20000};
  65. std::thread TAB{hammer_transfer,std::ref(A),std::ref(B),tran_ab,tries};
  66. std::thread TBA{hammer_transfer,std::ref(B),std::ref(A),tran_ba,tries};
  67. std::thread TAA{hammer_transfer,std::ref(A),std::ref(A),tran_aa,tries};
  68.  
  69. TAB.join();
  70. TBA.join();
  71. TAA.join();
  72.  
  73. const auto close_a{A.get_balance()};
  74. const auto close_b{B.get_balance()};
  75.  
  76. std::cout << "A Close:" << close_a<< '\n';
  77. std::cout << "B Close:" << close_b<< '\n';
  78.  
  79. int errors{0};
  80. if((close_a+close_b)!=(open_a+open_b)){
  81. std::cout << "ERROR: Money Leaked!\n";
  82. ++errors;
  83. }
  84. if(close_a!=(open_a+tries*(tran_ba-tran_ab)) ||
  85. close_b!=(open_b+tries*(tran_ab-tran_ba))
  86. ){
  87. std::cout << "ERROR: 'Lost' Transaction(s)\n";
  88. ++errors;
  89. }
  90. if(errors==0){
  91. std::cout << "* SUCCESS *\n";
  92. }else{
  93. std::cout << "** FAILED **\n";
  94. }
  95. std::cout << std::endl;
  96. return 0;
  97. }
  98.  
Success #stdin #stdout 0s 4312KB
stdin
Standard input is empty
stdout
A Open:200000
B Open:100000
A Close:60000
B Close:240000
* SUCCESS *