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