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