1// reproduce dead lock if compiled with -DREPRODUCE_BUG 2 3#include "../Mutex.h" 4 5#include <boost/noncopyable.hpp> 6 7#include <memory> 8#include <unordered_map> 9 10#include <assert.h> 11#include <stdio.h> 12#include <unistd.h> 13 14using std::string; 15 16void sleepMs(int ms) 17{ 18 usleep(ms * 1000); 19} 20 21class Stock : boost::noncopyable 22{ 23 public: 24 Stock(const string& name) 25 : name_(name) 26 { 27 printf("%s: Stock[%p] %s\n", muduo::CurrentThread::name(), this, name_.c_str()); 28 } 29 30 ~Stock() 31 { 32 printf("%s: ~Stock[%p] %s\n", muduo::CurrentThread::name(), this, name_.c_str()); 33 } 34 35 const string& key() const { return name_; } 36 37 private: 38 string name_; 39}; 40 41 42class StockFactory : boost::noncopyable 43{ 44 public: 45 46 std::shared_ptr<Stock> get(const string& key) 47 { 48 std::shared_ptr<Stock> pStock; 49 muduo::MutexLockGuard lock(mutex_); 50 std::weak_ptr<Stock>& wkStock = stocks_[key]; 51 pStock = wkStock.lock(); 52 if (!pStock) 53 { 54 pStock.reset(new Stock(key), 55 [this] (Stock* stock) { deleteStock(stock); }); 56 wkStock = pStock; 57 } 58 return pStock; 59 } 60 61 private: 62 63 void deleteStock(Stock* stock) 64 { 65 printf("%s: deleteStock[%p]\n", muduo::CurrentThread::name(), stock); 66 if (stock) 67 { 68 sleepMs(500); 69 if (mutex_.isLockedByThisThread()) 70 { 71 printf("WARNING: mutex_ is already locked by this thread, deadlock will happen.\n"); 72 } 73 muduo::MutexLockGuard lock(mutex_); 74 auto it = stocks_.find(stock->key()); 75 assert(it != stocks_.end()); 76#ifdef REPRODUCE_BUG 77 if (auto x = it->second.lock()) 78 { 79 assert(stock != x.get()); 80 printf("use_count = %ld\n", x.use_count()); 81 sleepMs(500); 82 printf("use_count = %ld\n", x.use_count()); 83 } 84 else 85 { 86 stocks_.erase(it); 87 } 88#else 89 if (it->second.expired()) 90 { 91 stocks_.erase(it); 92 } 93 else 94 { 95 printf("%s: %s is not expired\n", muduo::CurrentThread::name(), stock->key().c_str()); 96 } 97#endif 98 } 99 delete stock; // sorry, I lied 100 } 101 102 mutable muduo::MutexLock mutex_; 103 std::unordered_map<string, std::weak_ptr<Stock> > stocks_; 104}; 105 106void threadB(StockFactory* factory) 107{ 108 sleepMs(250); 109 auto stock = factory->get("MS"); 110 printf("%s: stockB %p\n", muduo::CurrentThread::name(), stock.get()); 111 112 sleepMs(500); 113 printf("%s: stockB destructs\n", muduo::CurrentThread::name()); 114} 115 116int main() 117{ 118 StockFactory factory; 119 muduo::Thread thr([&factory] { threadB(&factory); }, "thrB"); 120 thr.start(); 121 { 122 auto stock = factory.get("MS"); 123 printf("%s: stock %p\n", muduo::CurrentThread::name(), stock.get()); 124 } 125 thr.join(); 126} 127