16273720fSliuyunbin// reproduce race condition of Factory.cc if compiled with -DREPRODUCE_BUG 26273720fSliuyunbin 36273720fSliuyunbin#include "../Mutex.h" 46273720fSliuyunbin 56273720fSliuyunbin#include <boost/noncopyable.hpp> 66273720fSliuyunbin 76273720fSliuyunbin#include <memory> 86273720fSliuyunbin#include <unordered_map> 96273720fSliuyunbin 106273720fSliuyunbin#include <assert.h> 116273720fSliuyunbin#include <stdio.h> 126273720fSliuyunbin#include <unistd.h> 136273720fSliuyunbin 146273720fSliuyunbinusing std::string; 156273720fSliuyunbin 166273720fSliuyunbinvoid sleepMs(int ms) 176273720fSliuyunbin{ 186273720fSliuyunbin usleep(ms * 1000); 196273720fSliuyunbin} 206273720fSliuyunbin 216273720fSliuyunbinclass Stock : boost::noncopyable 226273720fSliuyunbin{ 236273720fSliuyunbin public: 246273720fSliuyunbin Stock(const string& name) 256273720fSliuyunbin : name_(name) 266273720fSliuyunbin { 276273720fSliuyunbin printf("%s: Stock[%p] %s\n", muduo::CurrentThread::name(), this, name_.c_str()); 286273720fSliuyunbin } 296273720fSliuyunbin 306273720fSliuyunbin ~Stock() 316273720fSliuyunbin { 326273720fSliuyunbin printf("%s: ~Stock[%p] %s\n", muduo::CurrentThread::name(), this, name_.c_str()); 336273720fSliuyunbin } 346273720fSliuyunbin 356273720fSliuyunbin const string& key() const { return name_; } 366273720fSliuyunbin 376273720fSliuyunbin private: 386273720fSliuyunbin string name_; 396273720fSliuyunbin}; 406273720fSliuyunbin 416273720fSliuyunbin 426273720fSliuyunbinclass StockFactory : boost::noncopyable 436273720fSliuyunbin{ 446273720fSliuyunbin public: 456273720fSliuyunbin 466273720fSliuyunbin std::shared_ptr<Stock> get(const string& key) 476273720fSliuyunbin { 486273720fSliuyunbin std::shared_ptr<Stock> pStock; 496273720fSliuyunbin muduo::MutexLockGuard lock(mutex_); 506273720fSliuyunbin std::weak_ptr<Stock>& wkStock = stocks_[key]; 516273720fSliuyunbin pStock = wkStock.lock(); 526273720fSliuyunbin if (!pStock) 536273720fSliuyunbin { 546273720fSliuyunbin pStock.reset(new Stock(key), 556273720fSliuyunbin [this] (Stock* stock) { deleteStock(stock); }); 566273720fSliuyunbin wkStock = pStock; 576273720fSliuyunbin } 586273720fSliuyunbin return pStock; 596273720fSliuyunbin } 606273720fSliuyunbin 616273720fSliuyunbin private: 626273720fSliuyunbin 636273720fSliuyunbin void deleteStock(Stock* stock) 646273720fSliuyunbin { 656273720fSliuyunbin printf("%s: deleteStock[%p]\n", muduo::CurrentThread::name(), stock); 666273720fSliuyunbin if (stock) 676273720fSliuyunbin { 686273720fSliuyunbin sleepMs(500); 696273720fSliuyunbin muduo::MutexLockGuard lock(mutex_); 706273720fSliuyunbin#ifdef REPRODUCE_BUG 716273720fSliuyunbin auto it = stocks_.find(stock->key()); 726273720fSliuyunbin assert(it != stocks_.end()); 736273720fSliuyunbin if (it->second.expired()) 746273720fSliuyunbin { 756273720fSliuyunbin stocks_.erase(it); 766273720fSliuyunbin } 776273720fSliuyunbin else 786273720fSliuyunbin { 796273720fSliuyunbin printf("%s: %s is not expired\n", muduo::CurrentThread::name(), stock->key().c_str()); 806273720fSliuyunbin } 816273720fSliuyunbin#else 826273720fSliuyunbin auto it = stocks_.find(stock->key()); 836273720fSliuyunbin if (it == stocks_.end()) 846273720fSliuyunbin { 856273720fSliuyunbin printf("%s: %s had been deleted\n", muduo::CurrentThread::name(), stock->key().c_str()); 866273720fSliuyunbin } 876273720fSliuyunbin else 886273720fSliuyunbin { 896273720fSliuyunbin if (it->second.expired()) 906273720fSliuyunbin { 916273720fSliuyunbin stocks_.erase(it); 926273720fSliuyunbin } 936273720fSliuyunbin else 946273720fSliuyunbin { 956273720fSliuyunbin printf("%s: %s is not expired\n", muduo::CurrentThread::name(), stock->key().c_str()); 966273720fSliuyunbin } 976273720fSliuyunbin } 986273720fSliuyunbin#endif 996273720fSliuyunbin } 1006273720fSliuyunbin delete stock; // sorry, I lied 1016273720fSliuyunbin } 1026273720fSliuyunbin 1036273720fSliuyunbin mutable muduo::MutexLock mutex_; 1046273720fSliuyunbin std::unordered_map<string, std::weak_ptr<Stock> > stocks_; 1056273720fSliuyunbin}; 1066273720fSliuyunbin 1076273720fSliuyunbinvoid threadB(StockFactory* factory) 1086273720fSliuyunbin{ 1096273720fSliuyunbin sleepMs(250); 1106273720fSliuyunbin auto stock = factory->get("MS"); 1116273720fSliuyunbin printf("%s: stock %p\n", muduo::CurrentThread::name(), stock.get()); 1126273720fSliuyunbin} 1136273720fSliuyunbin 1146273720fSliuyunbinint main() 1156273720fSliuyunbin{ 1166273720fSliuyunbin StockFactory factory; 1176273720fSliuyunbin muduo::Thread thr([&factory] { threadB(&factory); }, "thrB"); 1186273720fSliuyunbin thr.start(); 1196273720fSliuyunbin { 1206273720fSliuyunbin auto stock = factory.get("MS"); 1216273720fSliuyunbin printf("%s: stock %p\n", muduo::CurrentThread::name(), stock.get()); 1226273720fSliuyunbin } 1236273720fSliuyunbin thr.join(); 1246273720fSliuyunbin} 125