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