1// reproduce race condition of Factory.cc 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 muduo::MutexLockGuard lock(mutex_); 70#ifdef REPRODUCE_BUG 71 auto it = stocks_.find(stock->key()); 72 assert(it != stocks_.end()); 73 if (it->second.expired()) 74 { 75 stocks_.erase(it); 76 } 77 else 78 { 79 printf("%s: %s is not expired\n", muduo::CurrentThread::name(), stock->key().c_str()); 80 } 81#else 82 auto it = stocks_.find(stock->key()); 83 if (it == stocks_.end()) 84 { 85 printf("%s: %s had been deleted\n", muduo::CurrentThread::name(), stock->key().c_str()); 86 } 87 else 88 { 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 } 98#endif 99 } 100 delete stock; // sorry, I lied 101 } 102 103 mutable muduo::MutexLock mutex_; 104 std::unordered_map<string, std::weak_ptr<Stock> > stocks_; 105}; 106 107void threadB(StockFactory* factory) 108{ 109 sleepMs(250); 110 auto stock = factory->get("MS"); 111 printf("%s: stock %p\n", muduo::CurrentThread::name(), stock.get()); 112} 113 114int main() 115{ 116 StockFactory factory; 117 muduo::Thread thr([&factory] { threadB(&factory); }, "thrB"); 118 thr.start(); 119 { 120 auto stock = factory.get("MS"); 121 printf("%s: stock %p\n", muduo::CurrentThread::name(), stock.get()); 122 } 123 thr.join(); 124} 125